mirror of https://github.com/lianthony/NT4.0
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.
430 lines
10 KiB
430 lines
10 KiB
/*****************************************************************************
|
|
* *
|
|
* EXPAND.C *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1989. *
|
|
* All Rights reserved. *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Module Intent *
|
|
* This code compresses and decompresses bitmap bits, as well as the code *
|
|
* to expand Help 3.0 format bitmaps from disk image to the memory structure.*
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "skip.h"
|
|
|
|
#define fRLEBit 0x80
|
|
const int MAX_RUN = 127;
|
|
|
|
static int STDCALL LcbUncompressHb(PBYTE pbSrc, PBYTE pbDest, int cbSrc);
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HbmhExpandQv
|
|
-
|
|
* Purpose
|
|
* This function decompresses the bitmap from its disk format to an
|
|
* in memory bitmap header, including bitmap and hotspot data.
|
|
*
|
|
* Arguments
|
|
* A pointer to a buffer containing the bitmap data as read off disk.
|
|
*
|
|
* Returns
|
|
* A handle to the bitmap header. Returns hbmhOOM on out of memory.
|
|
* Note that this is the same as NULL. Also returns hbmhInvalid on
|
|
* invalid format. This handle is non-discardable, but the code that
|
|
* deals with qbmi->hbmh can deal with discardable blocks, so after
|
|
* initialization this can be made discardable.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
HBMH STDCALL HbmhExpandQv(void* qv)
|
|
{
|
|
PBMH qbmh;
|
|
BMH bmh;
|
|
int cbBits, cbUncompressedBits;
|
|
PBYTE pDst;
|
|
|
|
PBYTE pBase = (PBYTE) qv;
|
|
bmh.bmFormat = *((PBYTE) qv);
|
|
qv = QFromQCb(qv, sizeof(BYTE));
|
|
bmh.fCompressed = *((PBYTE) qv);
|
|
qv = QFromQCb(qv, sizeof(BYTE));
|
|
|
|
switch(bmh.bmFormat) {
|
|
case bmWbitmap:
|
|
case bmDIB:
|
|
qv = QVSkipQGB(qv, (&bmh.w.dib.biXPelsPerMeter));
|
|
qv = QVSkipQGB(qv, (&bmh.w.dib.biYPelsPerMeter));
|
|
qv = QVSkipQGA(qv, (&bmh.w.dib.biPlanes));
|
|
qv = QVSkipQGA(qv, (&bmh.w.dib.biBitCount));
|
|
|
|
qv = QVSkipQGB(qv, (&bmh.w.dib.biWidth));
|
|
qv = QVSkipQGB(qv, (&bmh.w.dib.biHeight));
|
|
qv = QVSkipQGB(qv, (&bmh.w.dib.biClrUsed));
|
|
qv = QVSkipQGB(qv, (&bmh.w.dib.biClrImportant));
|
|
|
|
qv = QVSkipQGB(qv, (&bmh.cbSizeBits));
|
|
qv = QVSkipQGB(qv, (&bmh.cbSizeExtra));
|
|
|
|
bmh.cbOffsetBits = *((DWORD *) qv);
|
|
qv = (PBYTE) qv + sizeof(DWORD);
|
|
bmh.cbOffsetExtra = *((DWORD *) qv);
|
|
qv = (PBYTE) qv + sizeof(DWORD);
|
|
|
|
// Fix up constant fields in DIB structure:
|
|
|
|
bmh.w.dib.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmh.w.dib.biCompression = 0L;
|
|
bmh.w.dib.biSizeImage = 0L;
|
|
|
|
// Determine size of bitmap header plus all data
|
|
|
|
if (bmh.fCompressed)
|
|
cbBits = LAlignLong (bmh.w.dib.biWidth * bmh.w.dib.biBitCount) *
|
|
bmh.w.dib.biHeight;
|
|
else
|
|
cbBits = bmh.cbSizeBits;
|
|
|
|
qbmh = (BMH*) lcCalloc(LcbSizeQbmh(&bmh) + cbBits
|
|
+ bmh.cbSizeExtra);
|
|
|
|
// Copy header and color table:
|
|
|
|
memmove(qbmh, &bmh, sizeof(BMH) - 2 * sizeof(RGBQUAD));
|
|
memmove(qbmh->rgrgb, qv, sizeof(RGBQUAD) * (int) bmh.w.dib.biClrUsed);
|
|
|
|
// Copy bits, decompressing if necessary:
|
|
|
|
qbmh->cbOffsetBits = LcbSizeQbmh(qbmh);
|
|
if (bmh.fCompressed == BMH_COMPRESS_30) {
|
|
qbmh->cbSizeBits = LcbUncompressHb(pBase + bmh.cbOffsetBits,
|
|
(PBYTE) QFromQCb(qbmh, qbmh->cbOffsetBits), bmh.cbSizeBits);
|
|
ASSERT(qbmh->cbSizeBits <= cbBits);
|
|
}
|
|
else if (bmh.fCompressed == BMH_COMPRESS_ZECK) {
|
|
qbmh->cbSizeBits = LcbUncompressZeck(
|
|
pBase + bmh.cbOffsetBits,
|
|
(PBYTE) qbmh + qbmh->cbOffsetBits, bmh.cbSizeBits);
|
|
ASSERT(qbmh->cbSizeBits <= cbBits);
|
|
}
|
|
else
|
|
memmove(QFromQCb(qbmh, qbmh->cbOffsetBits),
|
|
pBase + bmh.cbOffsetBits,
|
|
bmh.cbSizeBits);
|
|
qbmh->fCompressed = BMH_COMPRESS_NONE; // bits are no longer compressed
|
|
|
|
// Copy extra info:
|
|
|
|
qbmh->cbOffsetExtra = qbmh->cbOffsetBits + qbmh->cbSizeBits;
|
|
if (bmh.cbSizeExtra)
|
|
memmove((PBYTE) qbmh + qbmh->cbOffsetExtra,
|
|
pBase + bmh.cbOffsetExtra, bmh.cbSizeExtra);
|
|
break;
|
|
|
|
case bmWmetafile:
|
|
qv = QVSkipQGA(qv, (&bmh.w.mf.mm));
|
|
bmh.w.mf.xExt = *(INT16 *) qv;
|
|
qv = (PBYTE) qv + sizeof(INT16);
|
|
bmh.w.mf.yExt = *(INT16 *) qv;
|
|
qv = (PBYTE) qv + sizeof(INT16);
|
|
|
|
qv = QVSkipQGB(qv, &cbUncompressedBits);
|
|
qv = QVSkipQGB(qv, (&bmh.cbSizeBits));
|
|
qv = QVSkipQGB(qv, (&bmh.cbSizeExtra));
|
|
|
|
bmh.cbOffsetBits = *((DWORD *) qv);
|
|
qv = (PBYTE) qv + sizeof(DWORD);
|
|
bmh.cbOffsetExtra = *((DWORD *) qv);
|
|
qv = (PBYTE) qv + sizeof(DWORD);
|
|
|
|
qbmh = (BMH*) lcCalloc(sizeof(BMH) + bmh.cbSizeExtra);
|
|
|
|
*qbmh = bmh;
|
|
qbmh->cbOffsetExtra = sizeof(BMH);
|
|
memmove((PBYTE) qbmh + qbmh->cbOffsetExtra,
|
|
pBase + bmh.cbOffsetExtra, bmh.cbSizeExtra);
|
|
|
|
qbmh->w.mf.hMF =
|
|
(HMETAFILE) lcMalloc(cbUncompressedBits);
|
|
if (qbmh->w.mf.hMF == NULL) {
|
|
lcFree(qbmh);
|
|
return hbmhOOM;
|
|
}
|
|
|
|
// REVIEW: 18-Sep-1993 [ralphw] -- Don't lock!
|
|
|
|
pDst = (PBYTE) qbmh->w.mf.hMF;
|
|
switch (bmh.fCompressed) {
|
|
case BMH_COMPRESS_NONE:
|
|
memmove(pDst, pBase + bmh.cbOffsetBits, bmh.cbSizeBits);
|
|
break;
|
|
case BMH_COMPRESS_30:
|
|
LcbUncompressHb(pBase + bmh.cbOffsetBits, pDst, bmh.cbSizeBits);
|
|
break;
|
|
case BMH_COMPRESS_ZECK:
|
|
LcbUncompressZeck(pBase + bmh.cbOffsetBits,
|
|
pDst, bmh.cbSizeBits);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
// Invalidate this field, as the bits are in a separate handle:
|
|
|
|
qbmh->cbOffsetBits = 0L;
|
|
|
|
qbmh->cbSizeBits = cbUncompressedBits;
|
|
qbmh->fCompressed = BMH_COMPRESS_NONE;
|
|
|
|
break;
|
|
|
|
default:
|
|
return hbmhInvalid;
|
|
}
|
|
|
|
return (HBMH) qbmh;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FreeHbmh
|
|
-
|
|
* Purpose:
|
|
* This function frees a bitmap handle, whether it was created in
|
|
* FWritePbitmap() or HbmhExpandQv(). In the first case, metafile
|
|
* bits will be stored at the end of the bitmap handle, while in
|
|
* the second case, they will be stored in a separate handle.
|
|
*
|
|
* Arguments:
|
|
* hbmh -- handle to a bitmap.
|
|
*
|
|
* Returns:
|
|
* nothing.
|
|
*
|
|
***************************************************************************/
|
|
|
|
void STDCALL FreeHbmh(PBMH qbmh)
|
|
{
|
|
if (qbmh && qbmh != hbmhInvalid) {
|
|
|
|
// The bmh has not been discarded.
|
|
|
|
if (qbmh->bmFormat == bmWmetafile && qbmh->cbOffsetBits == 0) {
|
|
|
|
// Get rid of the current description of the metafile.
|
|
|
|
if (qbmh->w.mf.hMF != NULL)
|
|
lcFree(qbmh->w.mf.hMF);
|
|
}
|
|
lcFree(qbmh);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name RleCompress
|
|
-
|
|
* Purpose
|
|
* Compresses bitmap bits using RLE -- used when zeck compression is off
|
|
*
|
|
* Arguments
|
|
* pbSrc: pointer to source bits.
|
|
* pbDest: pointer to destination bits.
|
|
* cbSrc: Number of bytes in source.
|
|
*
|
|
* Returns
|
|
* Number of bytes in the destination. Guaranteed not to be
|
|
* more than 128/127 times cbSrc.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define GRIND_UPDATE 1024 // when to update grinder
|
|
|
|
int STDCALL RleCompress(PBYTE pbSrc, PBYTE pbDest, int cbSrc)
|
|
{
|
|
int cbRun, cb;
|
|
BYTE ch;
|
|
cGrind = 0;
|
|
|
|
PBYTE pbStart = pbDest;
|
|
|
|
while (cbSrc > 0) {
|
|
|
|
if (++cGrind == GRIND_UPDATE) {
|
|
cGrind = 0;
|
|
doGrind();
|
|
}
|
|
|
|
// Find next run of dissimilar bytes:
|
|
|
|
cbRun = 0;
|
|
if (cbSrc <= 2)
|
|
cbRun = cbSrc;
|
|
else {
|
|
while (pbSrc[cbRun] != pbSrc[cbRun + 1] ||
|
|
pbSrc[cbRun] != pbSrc[cbRun + 2])
|
|
if (++cbRun >= cbSrc - 2) {
|
|
cbRun = cbSrc;
|
|
break;
|
|
}
|
|
}
|
|
cbSrc -= cbRun;
|
|
|
|
// Output run of dissimilar bytes:
|
|
|
|
while (cbRun > 0) {
|
|
cb = MIN(cbRun, MAX_RUN);
|
|
*pbDest++ = ((BYTE) cb) | fRLEBit;
|
|
cbRun -= cb;
|
|
while (cb-- > 0)
|
|
*pbDest++ = *pbSrc++;
|
|
}
|
|
|
|
if (cbSrc == 0)
|
|
break;
|
|
|
|
// Find next run of identical bytes:
|
|
|
|
ch = *pbSrc;
|
|
cbRun = 1;
|
|
while (cbRun < cbSrc && ch == pbSrc[cbRun])
|
|
cbRun++;
|
|
|
|
cbSrc -= cbRun;
|
|
pbSrc += cbRun;
|
|
|
|
// Output run of identical bytes:
|
|
|
|
while (cbRun > 0) {
|
|
cb = MIN(cbRun, MAX_RUN);
|
|
*pbDest++ = (BYTE) cb;
|
|
*pbDest++ = ch;
|
|
cbRun -= cb;
|
|
}
|
|
}
|
|
|
|
return (int) (pbDest - pbStart);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name LcbOldUncompressHb
|
|
-
|
|
* Purpose
|
|
* This function is used only to decompress Help 2.5 bitmaps.
|
|
*
|
|
* Arguments
|
|
* pbSrc: Huge pointer to source bits.
|
|
* pbDest: Huge pointer to beginning of destination buffer.
|
|
* cbSrc: Number of compressed bytes in source.
|
|
* cbDest: Size of destination buffer.
|
|
*
|
|
* Returns
|
|
* Actual number of bytes copied to destination buffer, or -1 if
|
|
* buffer is too small.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
int pascal LcbOldUncompressHb(PBYTE pbSrc, PBYTE pbDest,
|
|
int cbSrc, int cbDest)
|
|
{
|
|
PBYTE pbStart;
|
|
WORD cbRun;
|
|
BYTE ch;
|
|
|
|
// Move pointers to the end of the buffers:
|
|
|
|
pbSrc += cbSrc;
|
|
pbDest += cbDest;
|
|
pbStart = pbDest;
|
|
|
|
while (cbSrc-- > 0) {
|
|
cbRun = *(--pbSrc);
|
|
cbDest -= (cbRun & ~fRLEBit);
|
|
if (cbDest < 0)
|
|
return -1;
|
|
|
|
if (cbRun & fRLEBit) {
|
|
cbRun -= fRLEBit;
|
|
cbSrc -= cbRun;
|
|
while (cbRun-- > 0)
|
|
*(--pbDest) = *(--pbSrc);
|
|
}
|
|
else {
|
|
ch = *(--pbSrc);
|
|
while (cbRun-- > 0)
|
|
*(--pbDest) = ch;
|
|
cbSrc--;
|
|
}
|
|
}
|
|
|
|
return (int) pbStart - (int) pbDest;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name LcbUncompressHb
|
|
-
|
|
* Purpose
|
|
* Decompresses the bits in pbSrc.
|
|
*
|
|
* Arguments
|
|
* pbSrc: Huge pointer to compressed bits.
|
|
* pbDest: Buffer to copy decompressed bits to.
|
|
* cbSrc: Number of bytes in pbSrc.
|
|
*
|
|
* Returns
|
|
* Number of bytes copied to pbDest. This can only be used for
|
|
* real mode error checking, as the maximum size of pbDest must
|
|
* be determined before decompression.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int STDCALL LcbUncompressHb(PBYTE pbSrc, PBYTE pbDest, int cbSrc)
|
|
{
|
|
PBYTE pbStart;
|
|
WORD cbRun;
|
|
BYTE ch;
|
|
|
|
pbStart = pbDest;
|
|
|
|
while (cbSrc-- > 0) {
|
|
cbRun = *pbSrc++;
|
|
if (cbRun & fRLEBit) {
|
|
cbRun -= fRLEBit;
|
|
cbSrc -= cbRun;
|
|
while (cbRun-- > 0)
|
|
*pbDest++ = *pbSrc++;
|
|
}
|
|
else {
|
|
ch = *pbSrc++;
|
|
while (cbRun-- > 0)
|
|
*pbDest++ = ch;
|
|
cbSrc--;
|
|
}
|
|
}
|
|
|
|
return (int) (pbDest - pbStart);
|
|
}
|