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.
1652 lines
72 KiB
1652 lines
72 KiB
#include <winerror.h>
|
|
|
|
/****************************************************************************/
|
|
/* abdapi.c */
|
|
/* */
|
|
/* Bitmap Decompression API functions */
|
|
/* */
|
|
/* Copyright(C) Microsoft Corporation 1996-1999 */
|
|
/****************************************************************************/
|
|
#define DC_EXTRACT_UINT16_UA(pA) ((unsigned short) (((PBYTE)(pA))[0]) | \
|
|
(unsigned short) ((((PBYTE)(pA))[1]) << 8) )
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: BDMemcpy */
|
|
/* */
|
|
/* Purpose: Copies a given number of bytes from source to destination. */
|
|
/* Source and destination may overlap, but copy is always */
|
|
/* performed upwards (from start address onwards). */
|
|
/* */
|
|
/* Params: pDst - pointer to destination */
|
|
/* pSrc - pointer to source data */
|
|
/* count - number of bytes to copy */
|
|
/****************************************************************************/
|
|
_inline void RDPCALL BDMemcpy(PBYTE pDst, PBYTE pSrc, unsigned int count)
|
|
{
|
|
#if defined(DC_DEBUG) || defined(DC_NO_UNALIGNED) || defined(_M_IA64)
|
|
unsigned int i;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("BDMemcpy");
|
|
|
|
/************************************************************************/
|
|
/* Bitmap decompression deliberately does overlapped memcpys, e.g. */
|
|
/* from the previous bitmap row to the current bitmap row for more than */
|
|
/* one row. */
|
|
/* */
|
|
/* When using the intrinsic memcpy (in the retail build) this works */
|
|
/* fine (in the current implementation of the MS compiler), as the copy */
|
|
/* always goes upwards through memory. However, if we use the MSVC */
|
|
/* run-time library (in the debug build) then memcpy appears to check */
|
|
/* for overlap and performs the copy so as to avoid clashing of src and */
|
|
/* dst (i.e. effectively performs a memmove). Therefore this does not */
|
|
/* do what we want, so manually copy the bytes in a debug build. */
|
|
/* */
|
|
/* This solution is a little unsatisfactory, as the operation of memset */
|
|
/* is officially undefined, but the performance-critical nature of */
|
|
/* this bit of code means that we really do want to use a memcpy. */
|
|
/* */
|
|
/* For non-Intel platforms, cannot rely on the above - so always use */
|
|
/* manual version. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#if defined(DC_DEBUG) || defined(DC_NO_UNALIGNED) || defined(_M_IA64)
|
|
/************************************************************************/
|
|
/* Debug build implementation. */
|
|
/************************************************************************/
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
*pDst++ = *pSrc++;
|
|
}
|
|
#else
|
|
/************************************************************************/
|
|
/* Retail build implementation. */
|
|
/************************************************************************/
|
|
DC_MEMCPY(pDst, pSrc, count);
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Utility macros for decoding codes */
|
|
/****************************************************************************/
|
|
#define CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) >= (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
hr = E_FAIL; \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_READ_ONE_BYTE_2ENDED(pBuffer, pStart, pEnd, hr, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) >= (BYTE*)(pEnd) || \
|
|
(BYTE*)(pBuffer) < (BYTE*)(pStart)) { \
|
|
BCTRACE( trc ); \
|
|
hr = E_FAIL; \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_WRITE_ONE_BYTE(pBuffer, pEnd, hr, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) >= (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
hr = E_FAIL; \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_WRITE_ONE_BYTE_NO_HR(pBuffer, pEnd, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) >= (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_READ_N_BYTES(pBuffer, pEnd, N, hr, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) + (N) > (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
hr = E_FAIL; \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_READ_N_BYTES_NO_HR(pBuffer, pEnd, N, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) + (N) > (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_READ_N_BYTES_2ENDED(pBuffer, pStart, pEnd, N, hr, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) + (N) > (BYTE*)(pEnd) || \
|
|
((BYTE*)(pBuffer) < (BYTE*)(pStart)) ) { \
|
|
BCTRACE( trc ); \
|
|
hr = E_FAIL; \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_WRITE_N_BYTES(pBuffer, pEnd, N, hr, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) + (N) > (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
hr = E_FAIL; \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define CHECK_WRITE_N_BYTES_NO_HR(pBuffer, pEnd, N, trc ) \
|
|
{\
|
|
if (((BYTE*)(pBuffer)) + (N) > (BYTE*)(pEnd)) { \
|
|
BCTRACE( trc ); \
|
|
DC_QUIT; \
|
|
} \
|
|
}
|
|
|
|
#define BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr, \
|
|
(TB, "Decompress reads one byte end of buffer; [p=0x%x pEnd=0x%x]", \
|
|
(pBuffer), (pEnd) ))
|
|
|
|
#define BD_CHECK_READ_ONE_BYTE_2ENDED(pBuffer, pStart, pEnd, hr ) \
|
|
CHECK_READ_ONE_BYTE_2ENDED(pBuffer, pStart, pEnd, hr, (TB, "Decompress reads one byte off end of buffer; [p=0x%x pStart=0x%x pEnd=0x%x]", \
|
|
(pBuffer), (pStart), (pEnd) ))
|
|
|
|
#define BD_CHECK_WRITE_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
CHECK_WRITE_ONE_BYTE(pBuffer, pEnd, hr, (TB, "Decompress writes one byte off end of buffer; [p=0x%x pEnd=0x%x]", \
|
|
(pBuffer), (pEnd) ))
|
|
|
|
#define BD_CHECK_READ_N_BYTES(pBuffer, pEnd, N, hr ) \
|
|
CHECK_READ_N_BYTES(pBuffer, pEnd, N, hr, (TB, "Decompress reads off end of buffer; [p=0x%x pEnd=0x%x N=%u]", \
|
|
(pBuffer), (pEnd), (ULONG)(N)))
|
|
|
|
#define BD_CHECK_READ_N_BYTES_2ENDED(pBuffer, pStart, pEnd, N, hr ) \
|
|
CHECK_READ_N_BYTES_2ENDED(pBuffer, pStart, pEnd, N, hr, (TB, "Decompress reads off end of buffer; [p=0x%x pStart=0x%x pEnd=0x%x N=%u]", \
|
|
(pBuffer), (pStart), (pEnd), (ULONG)(N) ))
|
|
|
|
#define BD_CHECK_WRITE_N_BYTES(pBuffer, pEnd, N, hr ) \
|
|
CHECK_WRITE_N_BYTES(pBuffer, pEnd, N, hr, (TB, "Decompress write off end of buffer; [p=0x%x pEnd=0x%x N=%u]", \
|
|
(pBuffer), (pEnd), (ULONG)(N)))
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Macros to extract the length from order codes */
|
|
/****************************************************************************/
|
|
#define EXTRACT_LENGTH(pBuffer, pEnd, length, hr) \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ & MAX_LENGTH_ORDER; \
|
|
if (length == 0) \
|
|
{ \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ + MAX_LENGTH_ORDER + 1; \
|
|
}
|
|
|
|
#define EXTRACT_LENGTH_LITE(pBuffer, pEnd, length, hr ) \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ & MAX_LENGTH_ORDER_LITE; \
|
|
if (length == 0) \
|
|
{ \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ + MAX_LENGTH_ORDER_LITE + 1; \
|
|
}
|
|
|
|
#define EXTRACT_LENGTH_FGBG(pBuffer, pEnd, length, hr ) \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ & MAX_LENGTH_ORDER; \
|
|
if (length == 0) \
|
|
{ \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ + 1; \
|
|
} \
|
|
else \
|
|
{ \
|
|
length = length << 3; \
|
|
}
|
|
|
|
#define EXTRACT_LENGTH_FGBG_LITE(pBuffer, pEnd, length, hr) \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ & MAX_LENGTH_ORDER_LITE; \
|
|
if (length == 0) \
|
|
{ \
|
|
BD_CHECK_READ_ONE_BYTE(pBuffer, pEnd, hr ) \
|
|
length = *pBuffer++ + 1; \
|
|
} \
|
|
else \
|
|
{ \
|
|
length = length << 3; \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Macro to store an FGBG image */
|
|
/* This macro expects that the function defines pDst, pEndDst, hr */
|
|
/* If there is not enough data to write the full run, this will set error */
|
|
/* and quit */
|
|
/****************************************************************************/
|
|
#define STORE_FGBG(xorbyte, fgbgChar, fgChar, bits) \
|
|
{ \
|
|
unsigned int numbits = bits; \
|
|
BD_CHECK_WRITE_N_BYTES( pDst, pEndDst, max(1, min(numbits, 8)), hr ) \
|
|
if (fgbgChar & 0x01) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x02) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x04) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x08) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x10) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x20) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x40) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
if (--numbits > 0) \
|
|
{ \
|
|
if (fgbgChar & 0x80) \
|
|
{ \
|
|
*pDst++ = (BYTE)(xorbyte ^ fgChar); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pDst++ = xorbyte; \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
#ifdef DC_HICOLOR
|
|
/****************************************************************************/
|
|
/* 8bpp decompression */
|
|
/****************************************************************************/
|
|
#define BCTRACE(string)
|
|
_inline HRESULT RDPCALL BDDecompressBitmap8( PBYTE pSrc,
|
|
PBYTE pDstBuffer,
|
|
unsigned int compressedDataSize,
|
|
unsigned int dstBufferSize,
|
|
BYTE bitmapBitsPerPel,
|
|
unsigned short rowDelta)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
unsigned int codeLength;
|
|
BYTE codeByte;
|
|
BYTE codeByte2;
|
|
BYTE decode;
|
|
BYTE decodeLite;
|
|
BYTE decodeMega;
|
|
BYTE fgChar;
|
|
PBYTE pDst;
|
|
PBYTE pEndSrc;
|
|
PBYTE pEndDst;
|
|
BOOL backgroundNeedsPel;
|
|
BOOL firstLine;
|
|
|
|
DC_BEGIN_FN("BDDecompressBitmap8");
|
|
|
|
pEndSrc = pSrc + compressedDataSize;
|
|
pDst = pDstBuffer;
|
|
pEndDst = pDst + dstBufferSize;
|
|
|
|
fgChar = 0xFF;
|
|
backgroundNeedsPel = FALSE;
|
|
firstLine = TRUE;
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Main decompression loop */
|
|
/* */
|
|
/************************************************************************/
|
|
while (pSrc < pEndSrc)
|
|
{
|
|
/********************************************************************/
|
|
/* While we are processing the first line we should keep a look out */
|
|
/* for the end of the line */
|
|
/********************************************************************/
|
|
if (firstLine)
|
|
{
|
|
if ((unsigned int)(pDst - pDstBuffer) >= rowDelta)
|
|
{
|
|
firstLine = FALSE;
|
|
backgroundNeedsPel = FALSE;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* Get the decode */
|
|
/********************************************************************/
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
decode = (BYTE)(*pSrc & CODE_MASK);
|
|
decodeLite = (BYTE)(*pSrc & CODE_MASK_LITE);
|
|
decodeMega = (BYTE)(*pSrc);
|
|
|
|
/********************************************************************/
|
|
/* BG RUN */
|
|
/********************************************************************/
|
|
if ((decode == CODE_BG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_BG_RUN))
|
|
{
|
|
if (decode == CODE_BG_RUN)
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
BCTRACE((TB, "Background run %u",codeLength));
|
|
|
|
if (!firstLine)
|
|
{
|
|
if (backgroundNeedsPel)
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr);
|
|
*pDst++ = (BYTE)(*(pDst - rowDelta) ^ fgChar);
|
|
codeLength--;
|
|
}
|
|
|
|
BD_CHECK_READ_N_BYTES_2ENDED(pDst-rowDelta, pDstBuffer, pEndDst, codeLength, hr)
|
|
BD_CHECK_WRITE_N_BYTES( pDst, pEndDst, codeLength, hr)
|
|
BDMemcpy(pDst, pDst-rowDelta, codeLength);
|
|
pDst += codeLength;
|
|
}
|
|
else
|
|
{
|
|
if (backgroundNeedsPel)
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr)
|
|
*pDst++ = fgChar;
|
|
codeLength--;
|
|
}
|
|
|
|
BD_CHECK_WRITE_N_BYTES( pDst, pEndDst, codeLength, hr)
|
|
memset(pDst, 0x00, codeLength);
|
|
pDst += codeLength;
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* A follow on BG run will need a pel inserted */
|
|
/****************************************************************/
|
|
backgroundNeedsPel = TRUE;
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* For any of the other runtypes a follow on BG run does not need */
|
|
/* a FG pel inserted */
|
|
/********************************************************************/
|
|
backgroundNeedsPel = FALSE;
|
|
|
|
/********************************************************************/
|
|
/* FGBG IMAGE */
|
|
/********************************************************************/
|
|
if ((decode == CODE_FG_BG_IMAGE) ||
|
|
(decodeLite == CODE_SET_FG_FG_BG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_FGBG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FGBG))
|
|
{
|
|
if ((decodeMega == CODE_MEGA_MEGA_FGBG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FGBG))
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
if (decode == CODE_FG_BG_IMAGE)
|
|
{
|
|
EXTRACT_LENGTH_FGBG(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH_FGBG_LITE(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
}
|
|
|
|
if ((decodeLite == CODE_SET_FG_FG_BG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FGBG))
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
fgChar = *pSrc++;
|
|
BCTRACE((TB, "Set FGBG image %u",codeLength));
|
|
}
|
|
else
|
|
{
|
|
BCTRACE((TB, "FGBG image %u",codeLength));
|
|
}
|
|
|
|
while (codeLength > 8)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
codeByte = *pSrc++;
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00, codeByte, fgChar, 8);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED( pDst-rowDelta, pDstBuffer, pEndDst, hr )
|
|
STORE_FGBG(*(pDst - rowDelta), codeByte, fgChar, 8);
|
|
}
|
|
codeLength -= 8;
|
|
}
|
|
if (codeLength > 0)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
codeByte = *pSrc++;
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00, codeByte, fgChar, codeLength);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED( pDst -rowDelta, pDstBuffer, pEndDst, hr )
|
|
STORE_FGBG(*(pDst - rowDelta),
|
|
codeByte,
|
|
fgChar,
|
|
codeLength);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* FG RUN */
|
|
/********************************************************************/
|
|
if ((decode == CODE_FG_RUN) ||
|
|
(decodeLite == CODE_SET_FG_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
|
|
{
|
|
if ((decodeMega == CODE_MEGA_MEGA_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
if (decode == CODE_FG_RUN)
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH_LITE(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* Push the old fgChar down to the ALT position */
|
|
/****************************************************************/
|
|
if ((decodeLite == CODE_SET_FG_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
BCTRACE((TB, "Set FG run %u",codeLength));
|
|
fgChar = *pSrc++;
|
|
}
|
|
else
|
|
{
|
|
BCTRACE((TB, "FG run %u",codeLength));
|
|
}
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr)
|
|
while (codeLength-- > 0)
|
|
{
|
|
if (!firstLine)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED((pDst -rowDelta), pDstBuffer, pEndDst, hr)
|
|
*pDst++ = (BYTE)(*(pDst - rowDelta) ^ fgChar);
|
|
}
|
|
else
|
|
{
|
|
*pDst++ = fgChar;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* DITHERED RUN */
|
|
/********************************************************************/
|
|
if ((decodeLite == CODE_DITHERED_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_DITHER))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_DITHER)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH_LITE(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
BCTRACE((TB, "Dithered run %u",codeLength));
|
|
|
|
BD_CHECK_READ_N_BYTES(pSrc, pEndSrc, 2, hr);
|
|
codeByte = *pSrc++;
|
|
codeByte2 = *pSrc++;
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength * 2, hr)
|
|
while (codeLength-- > 0)
|
|
{
|
|
*pDst++ = codeByte;
|
|
*pDst++ = codeByte2;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* COLOR IMAGE */
|
|
/********************************************************************/
|
|
if ((decode == CODE_COLOR_IMAGE) ||
|
|
(decodeMega == CODE_MEGA_MEGA_CLR_IMG))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_CLR_IMG)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
BCTRACE((TB, "Color image %u",codeLength));
|
|
|
|
BD_CHECK_READ_N_BYTES(pSrc, pEndSrc, codeLength, hr)
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr)
|
|
BDMemcpy(pDst, pSrc, codeLength);
|
|
|
|
pDst += codeLength;
|
|
pSrc += codeLength;
|
|
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* COLOR RUN */
|
|
/********************************************************************/
|
|
if ((decode == CODE_COLOR_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_COLOR_RUN))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_COLOR_RUN)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
BCTRACE((TB, "Color run %u",codeLength));
|
|
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr)
|
|
codeByte = *pSrc++;
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr)
|
|
memset(pDst, codeByte, codeLength);
|
|
pDst += codeLength;
|
|
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* If we get here then the code must be a special one */
|
|
/********************************************************************/
|
|
BCTRACE((TB, "Special code %#x",decodeMega));
|
|
switch (decodeMega)
|
|
{
|
|
case CODE_BLACK:
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
*pDst++ = 0x00;
|
|
}
|
|
break;
|
|
|
|
case CODE_WHITE:
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
*pDst++ = 0xFF;
|
|
}
|
|
break;
|
|
|
|
/****************************************************************/
|
|
/* Ignore the unreachable code warnings that follow */
|
|
/* Simply because we use the STORE_FGBG macro with a constant */
|
|
/* value */
|
|
/****************************************************************/
|
|
case CODE_SPECIAL_FGBG_1:
|
|
{
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00, SPECIAL_FGBG_CODE_1, fgChar, 8);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst-rowDelta, pDstBuffer, pEndDst, hr);
|
|
STORE_FGBG(*(pDst - rowDelta),
|
|
SPECIAL_FGBG_CODE_1,
|
|
fgChar,
|
|
8);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case CODE_SPECIAL_FGBG_2:
|
|
{
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00,
|
|
SPECIAL_FGBG_CODE_2,
|
|
fgChar,
|
|
8);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst-rowDelta, pDstBuffer, pEndDst, hr);
|
|
STORE_FGBG(*(pDst - rowDelta),
|
|
SPECIAL_FGBG_CODE_2,
|
|
fgChar,
|
|
8);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
BCTRACE((TB, "Invalid compression data %x",decodeMega));
|
|
}
|
|
break;
|
|
}
|
|
pSrc++;
|
|
}
|
|
|
|
BCTRACE((TB, "Decompressed to %d", pDst-pDstBuffer));
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* 15bpp decompression */
|
|
/****************************************************************************/
|
|
_inline HRESULT RDPCALL BDDecompressBitmap15(PBYTE pSrc,
|
|
PBYTE pDstBuffer,
|
|
unsigned int srcDataSize,
|
|
unsigned int dstBufferSize,
|
|
unsigned short rowDelta)
|
|
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "BDDecompressBitmap15"
|
|
|
|
/****************************************************************************/
|
|
/* Data type of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL unsigned short
|
|
|
|
/****************************************************************************/
|
|
/* 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) ((unsigned short) (((PBYTE)(pPos))[1]) | \
|
|
(unsigned short) ((((PBYTE)(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; \
|
|
(((PBYTE)(pPos))[1]) = (BYTE)( (val) & 0x00FF); \
|
|
(((PBYTE)(pPos))[0]) = (BYTE)(((val)>>8) & 0x00FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abdcom.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 decompression */
|
|
/****************************************************************************/
|
|
_inline HRESULT BDDecompressBitmap16(PBYTE pSrc,
|
|
PBYTE pDstBuffer,
|
|
unsigned int srcDataSize,
|
|
unsigned int dstBufferSize,
|
|
unsigned short rowDelta)
|
|
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "BDDecompressBitmap16"
|
|
|
|
/****************************************************************************/
|
|
/* Data type of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL unsigned short
|
|
|
|
/****************************************************************************/
|
|
/* 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) ((unsigned short) (((PBYTE)(pPos))[1]) | \
|
|
(unsigned short) ((((PBYTE)(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; \
|
|
(((PBYTE)(pPos))[1]) = (BYTE)( (val) & 0x00FF); \
|
|
(((PBYTE)(pPos))[0]) = (BYTE)(((val)>>8) & 0x00FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abdcom.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 decompression */
|
|
/****************************************************************************/
|
|
_inline HRESULT BDDecompressBitmap24(PBYTE pSrc,
|
|
PBYTE pDstBuffer,
|
|
unsigned int srcDataSize,
|
|
unsigned int dstBufferSize,
|
|
unsigned short rowDelta)
|
|
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "BDDecompressBitmap24"
|
|
|
|
/****************************************************************************/
|
|
/* 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) ( (unsigned short)(((PBYTE)(pPos))[2]) ) | \
|
|
(TSUINT32) (((unsigned short)(((PBYTE)(pPos))[1])) << 8) | \
|
|
(TSUINT32) (((TSUINT32)(((PBYTE)(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; \
|
|
(((PBYTE)(pPos))[2]) = (BYTE)((val) & 0x000000FF); \
|
|
(((PBYTE)(pPos))[1]) = (BYTE)(((val)>>8) & 0x000000FF); \
|
|
(((PBYTE)(pPos))[0]) = (BYTE)(((val)>>16) & 0x000000FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abdcom.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
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: BD_DecompressBitmap */
|
|
/* */
|
|
/* Purpose: Decompresses compressed bitmap data */
|
|
/* */
|
|
/* Params: IN - pCompressedData: pointer to compressed bitmap data */
|
|
/* OUT - pDstBitmap: pointer to buffer for decompressed data */
|
|
/* IN - srcDataSize: the compressed data size */
|
|
/* IN - bitmapBitsPerPel: the bits per pel of the data */
|
|
/****************************************************************************/
|
|
HRESULT BD_DecompressBitmap(
|
|
#ifndef DLL_DISP
|
|
PTSHARE_WD m_pTSWd,
|
|
#endif
|
|
PBYTE pCompressedData,
|
|
PBYTE pDstBuffer,
|
|
unsigned int srcDataSize,
|
|
unsigned int dstBufferSize,
|
|
unsigned int noBCHeader,
|
|
BYTE bitmapBitsPerPel,
|
|
unsigned short bitmapWidth,
|
|
unsigned short bitmapHeight)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PBYTE pSrc;
|
|
unsigned short rowDelta;
|
|
unsigned int compressedDataSize;
|
|
PTS_CD_HEADER pCompDataHeader;
|
|
#ifdef DC_NO_UNALIGNED
|
|
TS_CD_HEADER compDataHeader;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("BD_DecompressBitmap");
|
|
|
|
TRC_ASSERT( (pCompressedData != NULL),
|
|
(TB, "Invalid pCompressedData(%p)", pCompressedData) );
|
|
TRC_ASSERT( (pDstBuffer != NULL),
|
|
(TB, "Invalid pDstBuffer(%p)", pDstBuffer) );
|
|
TRC_ASSERT( (dstBufferSize != 0),
|
|
(TB, "Invalid dstBufferSize(%u)", dstBufferSize) );
|
|
TRC_ASSERT( (srcDataSize != 0),
|
|
(TB, "Invalid srcDataSize(%u)", srcDataSize) );
|
|
TRC_ASSERT( (dstBufferSize != 0),
|
|
(TB, "Invalid dstBufferSize(%u)", dstBufferSize) );
|
|
#ifdef DC_HICOLOR
|
|
#else
|
|
TRC_ASSERT( (bitmapBitsPerPel == 8),
|
|
(TB, "Invalid bitmapBitsPerPel(%u)", bitmapBitsPerPel) );
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* Initialize variables before main loop. */
|
|
/* */
|
|
/* No bitmap compression header included */
|
|
/************************************************************************/
|
|
if (noBCHeader)
|
|
{
|
|
compressedDataSize = srcDataSize;
|
|
pSrc = pCompressedData;
|
|
rowDelta = TS_BYTES_IN_SCANLINE(bitmapWidth,
|
|
bitmapBitsPerPel);
|
|
}
|
|
else
|
|
{
|
|
/************************************************************************/
|
|
/* Work out the location in the source data of each component. */
|
|
/* Make sure this is naturally aligned (for RISC platforms) */
|
|
/************************************************************************/
|
|
BD_CHECK_READ_N_BYTES(pCompressedData, pCompressedData + srcDataSize,
|
|
sizeof(TS_CD_HEADER), hr );
|
|
#ifdef DC_NO_UNALIGNED
|
|
DC_MEMCPY(&compDataHeader, pCompressedData, sizeof(TS_CD_HEADER));
|
|
pCompDataHeader = &compDataHeader;
|
|
#else
|
|
pCompDataHeader = (PTS_CD_HEADER)pCompressedData;
|
|
#endif
|
|
|
|
/********************************************************************/
|
|
/* Bitmap compression header included */
|
|
/********************************************************************/
|
|
compressedDataSize = pCompDataHeader->cbCompMainBodySize;
|
|
BD_CHECK_READ_N_BYTES(pCompressedData, pCompressedData + srcDataSize,
|
|
compressedDataSize + sizeof(TS_CD_HEADER), hr );
|
|
|
|
pSrc = pCompressedData + sizeof(TS_CD_HEADER);
|
|
rowDelta = pCompDataHeader->cbScanWidth;
|
|
if (rowDelta != TS_BYTES_IN_SCANLINE(bitmapWidth, bitmapBitsPerPel)) {
|
|
TRC_ABORT((TB, "rowDelta in TS_CD_HEADER incorrect "
|
|
"[got %u expected %u]", rowDelta,
|
|
TS_BYTES_IN_SCANLINE(bitmapWidth, bitmapBitsPerPel)));
|
|
hr = E_FAIL;
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Call the appropriate decompress function, based on the color depth */
|
|
/************************************************************************/
|
|
switch (bitmapBitsPerPel)
|
|
{
|
|
case 24:
|
|
{
|
|
hr = BDDecompressBitmap24 (pSrc,
|
|
pDstBuffer,
|
|
compressedDataSize,
|
|
dstBufferSize,
|
|
rowDelta);
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
{
|
|
hr = BDDecompressBitmap16 (pSrc,
|
|
pDstBuffer,
|
|
compressedDataSize,
|
|
dstBufferSize,
|
|
rowDelta);
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
{
|
|
hr = BDDecompressBitmap15 (pSrc,
|
|
pDstBuffer,
|
|
compressedDataSize,
|
|
dstBufferSize,
|
|
rowDelta);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
default:
|
|
{
|
|
hr = BDDecompressBitmap8 (pSrc,
|
|
pDstBuffer,
|
|
compressedDataSize,
|
|
dstBufferSize,
|
|
bitmapBitsPerPel,
|
|
rowDelta);
|
|
}
|
|
break;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
return hr;
|
|
}
|
|
|
|
#else
|
|
/****************************************************************************/
|
|
/* Name: BD_DecompressBitmap */
|
|
/* */
|
|
/* Purpose: Decompresses compressed bitmap data */
|
|
/* */
|
|
/* Params: IN - pCompressedData: pointer to compressed bitmap data */
|
|
/* OUT - pDstBitmap: pointer to buffer for decompressed data */
|
|
/* IN - srcDataSize: the compressed data size */
|
|
/* IN - bitmapBitsPerPel: the bits per pel of the data */
|
|
/****************************************************************************/
|
|
HRESULT RDPCALL BD_DecompressBitmap( PBYTE pCompressedData,
|
|
PBYTE pDstBuffer,
|
|
unsigned int srcDataSize,
|
|
unsigned int dstBufferSize,
|
|
unsigned int noBCHeader,
|
|
BYTE bitmapBitsPerPel,
|
|
unsigned short bitmapWidth,
|
|
unsigned short bitmapHeight )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
#ifdef DC_NO_UNALIGNED
|
|
TS_CD_HEADER compDataHeader;
|
|
#endif
|
|
PTS_CD_HEADER pCompDataHeader;
|
|
unsigned int compressedDataSize;
|
|
unsigned int codeLength;
|
|
BYTE codeByte;
|
|
BYTE codeByte2;
|
|
BYTE decode;
|
|
BYTE decodeLite;
|
|
BYTE decodeMega;
|
|
BYTE fgChar;
|
|
PBYTE pSrc;
|
|
PBYTE pDst;
|
|
PBYTE pEndSrc;
|
|
PBYTE pEndDst;
|
|
BOOL backgroundNeedsPel;
|
|
BOOL firstLine;
|
|
unsigned int rowDelta;
|
|
|
|
DC_BEGIN_FN("BD_DecompressBitmap");
|
|
|
|
TRC_ASSERT( (pCompressedData != NULL),
|
|
(TB, "Invalid pCompressedData(%p)", pCompressedData) );
|
|
TRC_ASSERT( (pDstBuffer != NULL),
|
|
(TB, "Invalid pDstBuffer(%p)", pDstBuffer) );
|
|
TRC_ASSERT( (srcDataSize != 0),
|
|
(TB, "Invalid srcDataSize(%u)", srcDataSize) );
|
|
TRC_ASSERT( (dstBufferSize != 0),
|
|
(TB, "Invalid dstBufferSize(%u)", dstBufferSize) );
|
|
TRC_ASSERT( (bitmapBitsPerPel == 8),
|
|
(TB, "Invalid bitmapBitsPerPel(%u)", bitmapBitsPerPel) );
|
|
|
|
/************************************************************************/
|
|
/* Trace the important parameters. */
|
|
/************************************************************************/
|
|
TRC_DBG((TB, "pData(%p) pDst(%p) cbSrc(%u) cbDst(%u)",
|
|
pCompressedData, pDstBuffer, srcDataSize, dstBufferSize));
|
|
|
|
/************************************************************************/
|
|
/* Initialize variables before main loop. */
|
|
/************************************************************************/
|
|
// no bitmap compression header included
|
|
if (noBCHeader) {
|
|
compressedDataSize = srcDataSize;
|
|
pSrc = pCompressedData;
|
|
rowDelta = TS_BYTES_IN_SCANLINE(bitmapWidth, bitmapBitsPerPel);
|
|
|
|
}
|
|
// bitmap compression header included
|
|
else {
|
|
/************************************************************************/
|
|
/* Work out the location in the source data of each component. */
|
|
/* Make sure this is naturally aligned (for RISC platforms) */
|
|
/************************************************************************/
|
|
BD_CHECK_READ_N_BYTES(pCompressedData, pCompressedData + srcDataSize,
|
|
sizeof(TS_CD_HEADER), hr );
|
|
|
|
#ifdef DC_NO_UNALIGNED
|
|
DC_MEMCPY(&compDataHeader, pCompressedData, sizeof(TS_CD_HEADER));
|
|
pCompDataHeader = &compDataHeader;
|
|
#else
|
|
pCompDataHeader = (PTS_CD_HEADER)pCompressedData;
|
|
#endif
|
|
|
|
compressedDataSize = pCompDataHeader->cbCompMainBodySize;
|
|
BD_CHECK_READ_N_BYTES(pCompressedData, pCompressedData + srcDataSize,
|
|
compressedDataSize + sizeof(TS_CD_HEADER), hr );
|
|
|
|
pSrc = pCompressedData + sizeof(TS_CD_HEADER);
|
|
rowDelta = pCompDataHeader->cbScanWidth;
|
|
if (rowDelta != TS_BYTES_IN_SCANLINE(bitmapWidth, bitmapBitsPerPel)) {
|
|
TRC_ABORT((TB, "rowDelta in TS_CD_HEADER incorrect "
|
|
"[got %u expected %u]", rowDelta,
|
|
TS_BYTES_IN_SCANLINE(bitmapWidth, bitmapBitsPerPel)));
|
|
hr = E_FAIL;
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
pEndSrc = pSrc + compressedDataSize;
|
|
pDst = pDstBuffer;
|
|
pEndDst = pDst + dstBufferSize;
|
|
|
|
fgChar = 0xFF;
|
|
backgroundNeedsPel = FALSE;
|
|
firstLine = TRUE;
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Main decompression loop */
|
|
/* */
|
|
/************************************************************************/
|
|
while(pSrc < pEndSrc)
|
|
{
|
|
/********************************************************************/
|
|
/* While we are processing the first line we should keep a look out */
|
|
/* for the end of the line */
|
|
/********************************************************************/
|
|
if (firstLine)
|
|
{
|
|
if ((unsigned int)(pDst - pDstBuffer) >= rowDelta)
|
|
{
|
|
firstLine = FALSE;
|
|
backgroundNeedsPel = FALSE;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* Get the decode */
|
|
/********************************************************************/
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
decode = (BYTE)(*pSrc & CODE_MASK);
|
|
decodeLite = (BYTE)(*pSrc & CODE_MASK_LITE);
|
|
decodeMega = (BYTE)(*pSrc);
|
|
|
|
/********************************************************************/
|
|
/* BG RUN */
|
|
/********************************************************************/
|
|
if ((decode == CODE_BG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_BG_RUN))
|
|
{
|
|
if (decode == CODE_BG_RUN)
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
TRC_DBG((TB, "Background run %u",codeLength));
|
|
|
|
if (!firstLine)
|
|
{
|
|
if (backgroundNeedsPel)
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr);
|
|
*pDst++ = (BYTE)(*(pDst - rowDelta) ^ fgChar);
|
|
codeLength--;
|
|
}
|
|
|
|
BD_CHECK_READ_N_BYTES_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, codeLength, hr);
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr);
|
|
|
|
BDMemcpy(pDst, pDst-rowDelta, codeLength);
|
|
pDst += codeLength;
|
|
}
|
|
else
|
|
{
|
|
if (backgroundNeedsPel)
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
*pDst++ = fgChar;
|
|
codeLength--;
|
|
}
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr);
|
|
memset(pDst, 0x00, codeLength);
|
|
pDst += codeLength;
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* A follow on BG run will need a pel inserted */
|
|
/****************************************************************/
|
|
backgroundNeedsPel = TRUE;
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* For any of the other runtypes a follow on BG run does not need */
|
|
/* a FG pel inserted */
|
|
/********************************************************************/
|
|
backgroundNeedsPel = FALSE;
|
|
|
|
/********************************************************************/
|
|
/* FGBG IMAGE */
|
|
/********************************************************************/
|
|
if ((decode == CODE_FG_BG_IMAGE) ||
|
|
(decodeLite == CODE_SET_FG_FG_BG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_FGBG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FGBG))
|
|
{
|
|
if ((decodeMega == CODE_MEGA_MEGA_FGBG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FGBG))
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
if (decode == CODE_FG_BG_IMAGE)
|
|
{
|
|
EXTRACT_LENGTH_FGBG(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH_FGBG_LITE(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
}
|
|
|
|
if ((decodeLite == CODE_SET_FG_FG_BG) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FGBG))
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
fgChar = *pSrc++;
|
|
TRC_DBG((TB, "Set FGBG image %u",codeLength));
|
|
}
|
|
else
|
|
{
|
|
TRC_DBG((TB, "FGBG image %u",codeLength));
|
|
}
|
|
|
|
while (codeLength > 8)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
codeByte = *pSrc++;
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00, codeByte, fgChar, 8);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr)
|
|
STORE_FGBG(*(pDst - rowDelta), codeByte, fgChar, 8);
|
|
}
|
|
codeLength -= 8;
|
|
}
|
|
if (codeLength > 0)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
codeByte = *pSrc++;
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00, codeByte, fgChar, codeLength);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr)
|
|
STORE_FGBG(*(pDst - rowDelta),
|
|
codeByte,
|
|
fgChar,
|
|
codeLength);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* FG RUN */
|
|
/********************************************************************/
|
|
if ((decode == CODE_FG_RUN) ||
|
|
(decodeLite == CODE_SET_FG_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
|
|
{
|
|
if ((decodeMega == CODE_MEGA_MEGA_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
if (decode == CODE_FG_RUN)
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH_LITE(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* Push the old fgChar down to the ALT position */
|
|
/****************************************************************/
|
|
if ((decodeLite == CODE_SET_FG_FG_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_SET_FG_RUN))
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
TRC_DBG((TB, "Set FG run %u",codeLength));
|
|
fgChar = *pSrc++;
|
|
}
|
|
else
|
|
{
|
|
TRC_DBG((TB, "FG run %u",codeLength));
|
|
}
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr)
|
|
while (codeLength-- > 0)
|
|
{
|
|
if (!firstLine)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr)
|
|
*pDst++ = (BYTE)(*(pDst - rowDelta) ^ fgChar);
|
|
}
|
|
else
|
|
{
|
|
*pDst++ = fgChar;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* DITHERED RUN */
|
|
/********************************************************************/
|
|
if ((decodeLite == CODE_DITHERED_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_DITHER))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_DITHER)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH_LITE(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
TRC_DBG((TB, "Dithered run %u",codeLength));
|
|
|
|
BD_CHECK_READ_N_BYTES(pSrc, pEndSrc, 2, hr);
|
|
codeByte = *pSrc++;
|
|
codeByte2 = *pSrc++;
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength * 2, hr)
|
|
while (codeLength-- > 0)
|
|
{
|
|
*pDst++ = codeByte;
|
|
*pDst++ = codeByte2;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* COLOR IMAGE */
|
|
/********************************************************************/
|
|
if ((decode == CODE_COLOR_IMAGE) ||
|
|
(decodeMega == CODE_MEGA_MEGA_CLR_IMG))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_CLR_IMG)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
TRC_DBG((TB, "Color image %u",codeLength));
|
|
|
|
BD_CHECK_READ_N_BYTES(pSrc, pEndSrc, codeLength, hr);
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr);
|
|
BDMemcpy(pDst, pSrc, codeLength);
|
|
|
|
pDst += codeLength;
|
|
pSrc += codeLength;
|
|
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* PACKED COLOR IMAGE */
|
|
/********************************************************************/
|
|
if ((decode == CODE_PACKED_COLOR_IMAGE) ||
|
|
(decodeMega == CODE_MEGA_MEGA_PACKED_CLR))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_PACKED_CLR)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
TRC_DBG((TB, "Packed color %u",codeLength));
|
|
|
|
if (bitmapBitsPerPel == 4)
|
|
{
|
|
unsigned int worklen = (codeLength)/2;
|
|
BYTE workchar;
|
|
BD_CHECK_READ_N_BYTES(pSrc, pEndSrc, worklen, hr);
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, worklen * 2, hr);
|
|
while (worklen--)
|
|
{
|
|
workchar = *pSrc++;
|
|
*pDst++ = (BYTE)(workchar >> 4);
|
|
*pDst++ = (BYTE)(workchar & 0x0F);
|
|
}
|
|
if (codeLength & 0x0001)
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
*pDst++ = (BYTE)(*pSrc++>>4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, "Don't support packed color for 8bpp"));
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* COLOR RUN */
|
|
/********************************************************************/
|
|
if ((decode == CODE_COLOR_RUN) ||
|
|
(decodeMega == CODE_MEGA_MEGA_COLOR_RUN))
|
|
{
|
|
if (decodeMega == CODE_MEGA_MEGA_COLOR_RUN)
|
|
{
|
|
BD_CHECK_READ_N_BYTES(pSrc+1, pEndSrc, 2, hr);
|
|
codeLength = DC_EXTRACT_UINT16_UA(pSrc+1);
|
|
pSrc += 3;
|
|
}
|
|
else
|
|
{
|
|
EXTRACT_LENGTH(pSrc, pEndSrc, codeLength, hr);
|
|
}
|
|
TRC_DBG((TB, "Color run %u",codeLength));
|
|
|
|
BD_CHECK_READ_ONE_BYTE(pSrc, pEndSrc, hr);
|
|
codeByte = *pSrc++;
|
|
|
|
BD_CHECK_WRITE_N_BYTES(pDst, pEndDst, codeLength, hr);
|
|
memset(pDst, codeByte, codeLength);
|
|
pDst += codeLength;
|
|
|
|
continue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* If we get here then the code must be a special one */
|
|
/********************************************************************/
|
|
TRC_DBG((TB, "Special code %#x",decodeMega));
|
|
switch (decodeMega)
|
|
{
|
|
case CODE_BLACK:
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
*pDst++ = 0x00;
|
|
}
|
|
break;
|
|
|
|
case CODE_WHITE:
|
|
{
|
|
BD_CHECK_WRITE_ONE_BYTE(pDst, pEndDst, hr);
|
|
*pDst++ = 0xFF;
|
|
}
|
|
break;
|
|
|
|
/****************************************************************/
|
|
/* Ignore the unreachable code warnings that follow */
|
|
/* Simply because we use the STORE_FGBG macro with a constant */
|
|
/* value */
|
|
/****************************************************************/
|
|
case CODE_SPECIAL_FGBG_1:
|
|
{
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00, SPECIAL_FGBG_CODE_1, fgChar, 8);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr)
|
|
STORE_FGBG(*(pDst - rowDelta),
|
|
SPECIAL_FGBG_CODE_1,
|
|
fgChar,
|
|
8);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case CODE_SPECIAL_FGBG_2:
|
|
{
|
|
if (firstLine)
|
|
{
|
|
STORE_FGBG(0x00,
|
|
SPECIAL_FGBG_CODE_2,
|
|
fgChar,
|
|
8);
|
|
}
|
|
else
|
|
{
|
|
BD_CHECK_READ_ONE_BYTE_2ENDED(pDst - rowDelta, pDstBuffer, pEndDst, hr)
|
|
STORE_FGBG(*(pDst - rowDelta),
|
|
SPECIAL_FGBG_CODE_2,
|
|
fgChar,
|
|
8);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
TRC_ERR((TB, "Invalid compression data %x",decodeMega));
|
|
}
|
|
break;
|
|
}
|
|
pSrc++;
|
|
}
|
|
|
|
TRC_DBG((TB, "Decompressed to %d", pDst-pDstBuffer));
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
#endif
|
|
|
|
#ifdef OS_WINDOWS
|
|
#pragma warning (default: 4127)
|
|
#endif /* OS_WINDOWS */
|
|
|