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.
750 lines
21 KiB
750 lines
21 KiB
/*--------------------------------------------------------------------------*\
|
|
| RLECIF.C - Interface to RLE Comressor |
|
|
|//@@BEGIN_MSINTERNAL |
|
|
| History: |
|
|
| 01/01/88 toddla Created |
|
|
| 10/30/90 davidmay Reorganized, rewritten somewhat. |
|
|
| 07/11/91 dannymi Un-hacked |
|
|
| 09/15/91 ToddLa Re-hacked |
|
|
| 09/18/91 DavidMay Separated from RLEC.C |
|
|
| 06/01/92 ToddLa Moved into a installable compressor |
|
|
|//@@END_MSINTERNAL |
|
|
| |
|
|
\*--------------------------------------------------------------------------*/
|
|
/**************************************************************************
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
* PURPOSE.
|
|
*
|
|
* Copyright (c) 1991 - 1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
**************************************************************************/
|
|
|
|
//@@BEGIN_MSINTERNAL |
|
|
#ifndef _WIN32
|
|
#include <win32.h>
|
|
#endif
|
|
//@@END_MSINTERNAL |
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <mmsystem.h>
|
|
|
|
#ifndef _INC_COMPDDK
|
|
#define _INC_COMPDDK 50 /* version number */
|
|
#endif
|
|
|
|
#include <vfw.h>
|
|
#include "msrle.h"
|
|
#include <stdarg.h>
|
|
|
|
//@@BEGIN_MSINTERNAL |
|
|
#ifdef UNICODE
|
|
#include "profile.h" // map to registry for NT
|
|
#endif
|
|
//@@END_MSINTERNAL |
|
|
|
|
RLESTATE DefaultRleState = {0, 0, -1, 187, 1500, 4};
|
|
|
|
#define FOURCC_DIB mmioFOURCC('D','I','B',' ')
|
|
#define FOURCC_RLE mmioFOURCC('M','R','L','E') //mmioFOURCC('R','L','E',' ')
|
|
|
|
#define TWOCC_DIB aviTWOCC('d','b')
|
|
#define TWOCC_RLE aviTWOCC('d','c')
|
|
#define TWOCC_DIBX aviTWOCC('d','x')
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
|
|
#pragma optimize("", off)
|
|
|
|
static BOOL NEAR PASCAL IsApp(LPTSTR szApp)
|
|
{
|
|
TCHAR ach[128];
|
|
int i;
|
|
HINSTANCE hInstance;
|
|
|
|
#ifdef _WIN32
|
|
hInstance = GetModuleHandle(NULL);
|
|
#else
|
|
_asm mov hInstance,ss
|
|
#endif
|
|
|
|
GetModuleFileName(hInstance, ach, sizeof(ach) / sizeof(ach[0]));
|
|
|
|
for (i = lstrlen(ach);
|
|
i > 0 && ach[i-1] != '\\' && ach[i-1] != '/' && ach[i] != ':';
|
|
i--)
|
|
;
|
|
|
|
return lstrcmpi(ach + i, szApp) == 0;
|
|
}
|
|
#pragma optimize("", on)
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
//
|
|
// RleLoad()
|
|
//
|
|
void NEAR PASCAL RleLoad()
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
//
|
|
// RleFree()
|
|
//
|
|
void NEAR PASCAL RleFree()
|
|
{
|
|
if (gRgbTol.hpTable)
|
|
GlobalFreePtr(gRgbTol.hpTable);
|
|
|
|
gRgbTol.hpTable = NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
|
|
//
|
|
// RleOpen() - open a instance of the rle compressor
|
|
//
|
|
PRLEINST NEAR PASCAL RleOpen()
|
|
{
|
|
PRLEINST pri;
|
|
|
|
//
|
|
// VIDEDIT Hack
|
|
//
|
|
// we dont want to see two "Microsoft RLE" compressors.
|
|
// so lie to VidEdit and fail to open.
|
|
//
|
|
|
|
if (GetModuleHandle(TEXT("MEDDIBS")) && IsApp(TEXT("VIDEDIT.EXE")))
|
|
return NULL;
|
|
|
|
pri = (PRLEINST)LocalAlloc(LPTR, sizeof(RLEINST));
|
|
|
|
if (pri)
|
|
{
|
|
RleSetState(pri, NULL, 0);
|
|
}
|
|
return pri;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
//
|
|
// RleClose() - close a instance of the rle compressor
|
|
//
|
|
DWORD NEAR PASCAL RleClose(PRLEINST pri)
|
|
{
|
|
if (!pri)
|
|
return FALSE;
|
|
|
|
if (pri->lpbiPrev) {
|
|
GlobalFreePtr(pri->lpbiPrev);
|
|
pri->lpbiPrev = NULL;
|
|
}
|
|
|
|
LocalFree((LOCALHANDLE)pri);
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
//
|
|
// RleGetState() - get the current state of the rle compressor
|
|
//
|
|
// will copy current state into passed buffer.
|
|
// returns the size in bytes required to store the entire state.
|
|
//
|
|
DWORD NEAR PASCAL RleGetState(PRLEINST pri, LPVOID pv, DWORD dwSize)
|
|
{
|
|
if (pv == NULL || dwSize == 0)
|
|
return sizeof(RLESTATE);
|
|
|
|
if (pri == NULL || dwSize < sizeof(RLESTATE))
|
|
return 0;
|
|
|
|
*(LPRLESTATE)pv = pri->RleState;
|
|
return sizeof(RLESTATE);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
//
|
|
// RleSetState() - sets the current state of the rle compressor
|
|
//
|
|
DWORD NEAR PASCAL RleSetState(PRLEINST pri, LPVOID pv, DWORD dwSize)
|
|
{
|
|
if (pv == NULL || dwSize == 0)
|
|
{
|
|
pv = &DefaultRleState;
|
|
dwSize = sizeof(RLESTATE);
|
|
}
|
|
|
|
if (pri == NULL || dwSize < sizeof(RLESTATE))
|
|
return 0;
|
|
|
|
pri->RleState = *(LPRLESTATE)pv;
|
|
return sizeof(RLESTATE);
|
|
}
|
|
|
|
#if !defined NUMELMS
|
|
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
|
|
#endif
|
|
|
|
#if defined _WIN32 && !defined UNICODE
|
|
|
|
int LoadUnicodeString(HINSTANCE hinst, UINT wID, LPWSTR lpBuffer, int cchBuffer)
|
|
{
|
|
char ach[128];
|
|
int i;
|
|
|
|
i = LoadString(hinst, wID, ach, sizeof(ach));
|
|
|
|
if (i > 0)
|
|
MultiByteToWideChar(CP_ACP, 0, ach, -1, lpBuffer, cchBuffer);
|
|
|
|
return i;
|
|
}
|
|
|
|
#else
|
|
#define LoadUnicodeString LoadString
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleGetInfo(PRLEINST pri, ICINFO FAR *icinfo, DWORD dwSize)
|
|
{
|
|
if (icinfo == NULL)
|
|
return sizeof(ICINFO);
|
|
|
|
if (dwSize < sizeof(ICINFO))
|
|
return 0;
|
|
|
|
icinfo->dwSize = sizeof(ICINFO);
|
|
icinfo->fccType = ICTYPE_VIDEO;
|
|
icinfo->fccHandler = FOURCC_RLE;
|
|
icinfo->dwFlags = VIDCF_QUALITY | // supports quality
|
|
VIDCF_TEMPORAL | // supports inter-frame
|
|
VIDCF_CRUNCH; // can crunch to a data rate
|
|
icinfo->dwVersion = ICVERSION;
|
|
|
|
LoadUnicodeString(ghModule, IDS_DESCRIPTION, icinfo->szDescription, NUMELMS(icinfo->szDescription));
|
|
LoadUnicodeString(ghModule, IDS_NAME, icinfo->szName, NUMELMS(icinfo->szName));
|
|
|
|
return sizeof(ICINFO);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleCompressQuery(PRLEINST pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
//
|
|
// determine if the input DIB data is in a format we like.
|
|
//
|
|
if (lpbiIn == NULL ||
|
|
lpbiIn->biBitCount != 8 ||
|
|
lpbiIn->biCompression != BI_RGB)
|
|
return (DWORD)ICERR_BADFORMAT;
|
|
|
|
//
|
|
// are we being asked to query just the input format?
|
|
//
|
|
if (lpbiOut == NULL)
|
|
return ICERR_OK;
|
|
|
|
//
|
|
// make sure we can handle the format to compress to also.
|
|
//
|
|
if (lpbiOut->biCompression != BI_RLE8 || // must be rle format
|
|
lpbiOut->biBitCount != 8 || // must be 8bpp
|
|
lpbiOut->biWidth != lpbiIn->biWidth || // must be 1:1 (no stretch)
|
|
lpbiOut->biHeight != lpbiIn->biHeight)
|
|
return (DWORD)ICERR_BADFORMAT;
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleCompressGetFormat(PRLEINST pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
DWORD dw;
|
|
DWORD dwClrUsed;
|
|
|
|
if (dw = RleCompressQuery(pri, lpbiIn, NULL))
|
|
return dw;
|
|
|
|
dwClrUsed = lpbiIn->biClrUsed;
|
|
if (dwClrUsed == 0) {
|
|
dwClrUsed = 256;
|
|
}
|
|
dw = lpbiIn->biSize + (int)dwClrUsed * sizeof(RGBQUAD);
|
|
|
|
//
|
|
// if lpbiOut == NULL then, return the size required to hold a output
|
|
// format
|
|
//
|
|
if (lpbiOut == NULL)
|
|
return dw;
|
|
|
|
hmemcpy(lpbiOut, lpbiIn, dw);
|
|
|
|
lpbiOut->biBitCount = 8;
|
|
lpbiOut->biCompression = BI_RLE8;
|
|
lpbiOut->biSizeImage = RleCompressGetSize(pri, lpbiIn, lpbiOut);
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleCompressBegin(PRLEINST pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
DWORD dw;
|
|
|
|
if (dw = RleCompressQuery(pri, lpbiIn, lpbiOut))
|
|
return dw;
|
|
|
|
if (pri->lpbiPrev) {
|
|
GlobalFreePtr(pri->lpbiPrev);
|
|
pri->lpbiPrev = NULL;
|
|
}
|
|
|
|
pri->iStart = 0;
|
|
pri->lLastParm = 0L;
|
|
|
|
pri->fCompressBegin = TRUE;
|
|
|
|
MakeRgbTable(lpbiIn);
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleCompressGetSize(PRLEINST pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
int dx,dy;
|
|
|
|
//
|
|
// we assume RLE data will never be twice the size of a full frame.
|
|
//
|
|
dx = (int)lpbiIn->biWidth;
|
|
dy = (int)lpbiIn->biHeight;
|
|
|
|
return (DWORD)(UINT)dx * (DWORD)(UINT)dy * 2;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleCompress(PRLEINST pri, ICCOMPRESS FAR *icinfo, DWORD dwSize)
|
|
{
|
|
DWORD dw;
|
|
BOOL fFrameHalvingOccurred = FALSE;
|
|
|
|
LPBITMAPINFOHEADER lpbi;
|
|
|
|
if (!pri->fCompressBegin)
|
|
{
|
|
if (dw = RleCompressBegin(pri, icinfo->lpbiInput, icinfo->lpbiOutput))
|
|
return dw;
|
|
|
|
pri->fCompressBegin = FALSE;
|
|
}
|
|
|
|
//
|
|
// we can compress in one of two ways:
|
|
//
|
|
// if a frame size is given (>0) then call CrunchDib using the passed
|
|
// quality as the "frame half" setting.
|
|
//
|
|
// if a frame size is not given (==0) then use the passed quality
|
|
// as the tolerance and do a normal RleDeltaFrame()
|
|
//
|
|
|
|
if (icinfo->dwQuality == ICQUALITY_DEFAULT)
|
|
icinfo->dwQuality = QUALITY_DEFAULT;
|
|
|
|
if (icinfo->dwFrameSize > 0)
|
|
{
|
|
dw = ICQUALITY_HIGH - icinfo->dwQuality;
|
|
|
|
pri->RleState.lMaxFrameSize = icinfo->dwFrameSize;
|
|
pri->RleState.lMinFrameSize = icinfo->dwFrameSize - 500;
|
|
pri->RleState.tolMax = dw;
|
|
pri->RleState.tolSpatial = dw / 8;
|
|
pri->RleState.tolTemporal = ADAPTIVE;
|
|
|
|
// SplitDib makes really ugly artifacts by splitting the frame into who knows
|
|
// how many pieces which will be pieced together like a bad jigsaw puzzle where
|
|
// each piece is from a different picture. I decided never to use this method
|
|
// of compression.
|
|
#if 0
|
|
if (dw == 0)
|
|
{
|
|
pri->RleState.tolSpatial = 0;
|
|
pri->RleState.tolTemporal = 0;
|
|
|
|
SplitDib(pri,
|
|
icinfo->lpbiOutput, icinfo->lpOutput,
|
|
icinfo->lpbiPrev, icinfo->lpPrev,
|
|
icinfo->lpbiInput, icinfo->lpInput);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
CrunchDib(pri,
|
|
icinfo->lpbiOutput, icinfo->lpOutput,
|
|
icinfo->lpbiPrev, icinfo->lpPrev,
|
|
icinfo->lpbiInput, icinfo->lpInput);
|
|
}
|
|
|
|
lpbi = icinfo->lpbiOutput;
|
|
|
|
if (lpbi->biCompression == BI_DIBX)
|
|
fFrameHalvingOccurred = TRUE;
|
|
|
|
if (icinfo->lpckid)
|
|
{
|
|
if (fFrameHalvingOccurred)
|
|
*icinfo->lpckid = TWOCC_DIBX;
|
|
else
|
|
*icinfo->lpckid = TWOCC_RLE;
|
|
}
|
|
|
|
lpbi->biCompression = BI_RLE8; // biSizeImage is filled in
|
|
}
|
|
else
|
|
{
|
|
dw = ICQUALITY_HIGH - icinfo->dwQuality;
|
|
|
|
pri->RleState.tolSpatial = dw;
|
|
pri->RleState.tolTemporal = dw / 8;
|
|
|
|
RleDeltaFrame(
|
|
icinfo->lpbiOutput, icinfo->lpOutput,
|
|
icinfo->lpbiPrev, icinfo->lpPrev,
|
|
icinfo->lpbiInput, icinfo->lpInput,
|
|
0,-1,
|
|
pri->RleState.tolTemporal,
|
|
pri->RleState.tolSpatial,
|
|
pri->RleState.iMaxRunLen,4);
|
|
|
|
if (icinfo->lpckid)
|
|
*icinfo->lpckid = TWOCC_RLE;
|
|
}
|
|
|
|
//
|
|
// set the AVI index flags,
|
|
//
|
|
// make it a keyframe, if no previous frame
|
|
//
|
|
if (icinfo->lpdwFlags) {
|
|
if (icinfo->lpbiPrev == NULL && !fFrameHalvingOccurred)
|
|
*icinfo->lpdwFlags |= AVIIF_TWOCC | AVIIF_KEYFRAME;
|
|
else
|
|
*icinfo->lpdwFlags |= AVIIF_TWOCC;
|
|
}
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleCompressEnd(PRLEINST pri)
|
|
{
|
|
pri->fCompressBegin = FALSE;
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleDecompressQuery(RLEINST * pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
//
|
|
// determine if the input DIB data is in a format we like.
|
|
// We like all RGB. We like 8bit RLE.
|
|
//
|
|
if (lpbiIn == NULL ||
|
|
(lpbiIn->biBitCount != 8 && lpbiIn->biCompression == BI_RLE8) ||
|
|
(lpbiIn->biCompression != BI_RGB && lpbiIn->biCompression != BI_RLE8))
|
|
return (DWORD)ICERR_BADFORMAT;
|
|
|
|
//
|
|
// are we being asked to query just the input format?
|
|
//
|
|
if (lpbiOut == NULL)
|
|
return ICERR_OK;
|
|
|
|
//
|
|
// make sure we can handle the format to decompress too.
|
|
//
|
|
if (lpbiOut->biCompression != BI_RGB || // must be full dib
|
|
lpbiOut->biBitCount != lpbiIn->biBitCount ||// must match
|
|
lpbiOut->biWidth != lpbiIn->biWidth || // must be 1:1 (no stretch)
|
|
lpbiOut->biHeight != lpbiIn->biHeight)
|
|
return (DWORD)ICERR_BADFORMAT;
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleDecompressGetFormat(RLEINST * pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
DWORD dw;
|
|
|
|
if (dw = RleDecompressQuery(pri, lpbiIn, NULL))
|
|
return dw;
|
|
|
|
dw = lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
|
|
|
|
//
|
|
// if lpbiOut == NULL then, return the size required to hold a output
|
|
// format
|
|
//
|
|
if (lpbiOut == NULL)
|
|
return dw;
|
|
|
|
hmemcpy(lpbiOut, lpbiIn, dw);
|
|
|
|
lpbiOut->biBitCount = lpbiIn->biBitCount;
|
|
lpbiOut->biCompression = BI_RGB;
|
|
lpbiOut->biSizeImage = lpbiIn->biHeight * DibWidthBytes(lpbiIn);
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleDecompressBegin(RLEINST * pri, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
DWORD dw;
|
|
|
|
if (dw = RleDecompressQuery(pri, lpbiIn, lpbiOut))
|
|
return dw;
|
|
|
|
pri->fDecompressBegin = TRUE;
|
|
|
|
// Make sure we know the size of an uncompressed DIB
|
|
if (lpbiOut->biSizeImage == 0)
|
|
lpbiOut->biSizeImage = lpbiOut->biHeight * DibWidthBytes(lpbiOut);
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleDecompress(RLEINST * pri, ICDECOMPRESS FAR *icinfo, DWORD dwSize)
|
|
{
|
|
DWORD dw;
|
|
|
|
if (!pri->fDecompressBegin)
|
|
{
|
|
if (dw = RleDecompressBegin(pri, icinfo->lpbiInput, icinfo->lpbiOutput))
|
|
return dw;
|
|
|
|
pri->fDecompressBegin = FALSE;
|
|
}
|
|
|
|
//
|
|
// handle a decompress of 'DIB ' (ie full frame) data. Just return it.
|
|
// It may be disguised an an RLE. We can tell by how big it is
|
|
//
|
|
if (icinfo->lpbiInput->biCompression == BI_RGB ||
|
|
icinfo->lpbiInput->biSizeImage == icinfo->lpbiOutput->biSizeImage)
|
|
{
|
|
hmemcpy(icinfo->lpOutput, icinfo->lpInput,
|
|
icinfo->lpbiInput->biSizeImage);
|
|
return ICERR_OK;
|
|
}
|
|
|
|
DecodeRle(icinfo->lpbiOutput, icinfo->lpOutput, icinfo->lpInput, icinfo->lpbiInput->biSizeImage);
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL RleDecompressEnd(RLEINST * pri)
|
|
{
|
|
pri->fDecompressBegin = FALSE;
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
DecodeRle - 'C' version
|
|
|
|
Play back a RLE buffer into a DIB buffer
|
|
|
|
returns
|
|
none
|
|
|
|
***************************************************************************/
|
|
|
|
void NEAR PASCAL DecodeRle(LPBITMAPINFOHEADER lpbi, LPVOID lp, LPVOID lpRle, DWORD dwInSize)
|
|
{
|
|
UINT cnt;
|
|
BYTE b;
|
|
UINT x;
|
|
UINT dx,dy;
|
|
UINT wWidthBytes;
|
|
DWORD dwOutSize;
|
|
DWORD dwJump;
|
|
|
|
#define RLE_ESCAPE 0
|
|
#define RLE_EOL 0
|
|
#define RLE_EOF 1
|
|
#define RLE_JMP 2
|
|
#define RLE_RUN 3
|
|
|
|
#ifndef _WIN32
|
|
extern FAR PASCAL __WinFlags;
|
|
#define WinFlags (UINT)(&__WinFlags)
|
|
//
|
|
// this uses ASM code found in RLEA.ASM
|
|
//
|
|
if (!(WinFlags & WF_CPU286))
|
|
DecodeRle386(lpbi, lp, lpRle);
|
|
else if (lpbi->biSizeImage < 65536l)
|
|
DecodeRle286(lpbi, lp, lpRle);
|
|
else
|
|
#endif
|
|
{
|
|
BYTE _huge *pb = lp;
|
|
BYTE _huge *prle = lpRle;
|
|
|
|
#define EatOutput(_x_) \
|
|
{ \
|
|
if (dwOutSize < (_x_)) { \
|
|
return; \
|
|
} \
|
|
dwOutSize -= (_x_); \
|
|
}
|
|
#define EatInput(_x_) \
|
|
{ \
|
|
if (dwInSize < (_x_)) { \
|
|
return; \
|
|
} \
|
|
dwInSize -= (_x_); \
|
|
}
|
|
|
|
if (lpbi->biHeight <= 0) {
|
|
return;
|
|
}
|
|
wWidthBytes = (UINT)lpbi->biWidth+3 & ~3;
|
|
dwOutSize = wWidthBytes * (DWORD)lpbi->biHeight;
|
|
|
|
x = 0;
|
|
|
|
for (;;)
|
|
{
|
|
EatInput(2);
|
|
cnt = (UINT)*prle++;
|
|
b = *prle++;
|
|
|
|
if (cnt == RLE_ESCAPE)
|
|
{
|
|
switch (b)
|
|
{
|
|
case RLE_EOF:
|
|
return;
|
|
|
|
case RLE_EOL:
|
|
EatOutput(wWidthBytes - x);
|
|
pb += wWidthBytes - x;
|
|
x = 0;
|
|
break;
|
|
|
|
case RLE_JMP:
|
|
EatInput(2);
|
|
dx = (UINT)*prle++;
|
|
dy = (UINT)*prle++;
|
|
|
|
dwJump = (DWORD)wWidthBytes * dy + dx;
|
|
EatOutput(dwJump);
|
|
pb += dwJump;
|
|
x += dx;
|
|
|
|
break;
|
|
|
|
default:
|
|
cnt = b;
|
|
EatOutput(cnt);
|
|
EatInput(cnt);
|
|
x += cnt;
|
|
// If the count was sufficiently large it would be worthwhile
|
|
// using an inline memcpy function. The code could
|
|
// be faster. Even doing this as a series of word
|
|
// moves would be quicker. However, RLE is not the highest
|
|
// priority.
|
|
while (cnt-- > 0)
|
|
*pb++ = *prle++; // copy
|
|
|
|
if (b & 1) {
|
|
EatInput(1);
|
|
prle++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x += cnt;
|
|
|
|
// If the count was sufficiently large it would be worthwhile
|
|
// using an inline memset function. The code could
|
|
// be faster. Even doing this as a series of word
|
|
// moves would be quicker. However, RLE is not the highest
|
|
// priority.
|
|
#if 1
|
|
// at least on the x86... this way persuades the compiler
|
|
// to use registers more effectively through the whole of
|
|
// the decode routine
|
|
EatOutput(cnt);
|
|
while (cnt-- > 0) {
|
|
*pb++ = b; // set
|
|
}
|
|
|
|
#else // the alternative
|
|
memset(pb, b, cnt);
|
|
pb += cnt;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void FAR cdecl dprintf(LPSTR szFormat, ...)
|
|
{
|
|
char ach[256];
|
|
va_list va;
|
|
|
|
static BOOL fDebug = -1;
|
|
|
|
if (fDebug == -1)
|
|
fDebug = GetProfileIntA("Debug", "MSRLE", FALSE);
|
|
|
|
if (!fDebug)
|
|
return;
|
|
|
|
lstrcpyA(ach, "MSRLE: ");
|
|
va_start(va, szFormat);
|
|
wvsprintfA(ach+7, szFormat, va);
|
|
va_end(va);
|
|
lstrcatA(ach, "\r\n");
|
|
|
|
OutputDebugStringA(ach);
|
|
}
|
|
|
|
#endif
|