/***************************************************************************** * * * 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.* * * ****************************************************************************** * * * Testing * * * ****************************************************************************** * * * Current Owner: Larry Powelson * * * ****************************************************************************** * * * Historical comments (optional): * 26-Jan-1991 RussPJ Made hbma's originally non-discardable, though * many routines make the discardable after first use. * * ****************************************************************************** * * * Released by Development: 11/13/90 * * * *****************************************************************************/ #include "help.h" #include "inc\_bitmap.h" /***************************************************************************** * * * Defines * * * *****************************************************************************/ #define fRLEBit 0x80 #define cbMaxRun 127 /*************************************************************************** * - 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 * ***************************************************************************/ #ifdef _X86_ HBMH STDCALL HbmhExpandQv(LPVOID qv) #else HBMH STDCALL HbmhExpandQv(LPVOID qv, int isdff) #endif { HBMH hbmh; QBMH qbmh; BMH bmh; LPBYTE qbBase; LONG lcbBits, lcbUncompressedBits; BYTE HUGE * rbDest; qbBase = qv; #ifdef _X86_ bmh.bmFormat = *((BYTE *) qv); qv = RFromRCb( qv, sizeof( BYTE )); bmh.fCompressed = *((BYTE *) qv); qv = RFromRCb( qv, sizeof( BYTE )); #else qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_BYTE, &bmh.bmFormat, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_BYTE, &bmh.fCompressed, qv)); #endif switch(bmh.bmFormat) { case bmWbitmap: case bmDIB: #ifdef _X86_ 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.lcbSizeBits)); qv = QVSkipQGB(qv, (&bmh.lcbSizeExtra)); bmh.lcbOffsetBits = *((DWORD *) qv); qv = RFromRCb(qv, sizeof(DWORD)); bmh.lcbOffsetExtra = *((DWORD *) qv); qv = RFromRCb(qv, sizeof(DWORD)); #else qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.w.dib.biXPelsPerMeter, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.w.dib.biYPelsPerMeter, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GA, &bmh.w.dib.biPlanes, qv) ); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GA, &bmh.w.dib.biBitCount, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.w.dib.biWidth, qv)) ; qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.w.dib.biHeight, qv) ); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.w.dib.biClrUsed, qv )); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.w.dib.biClrImportant, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.lcbSizeBits, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.lcbSizeExtra, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_DWORD, &bmh.lcbOffsetBits, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_DWORD, &bmh.lcbOffsetExtra, qv)); #endif // Fix up constant fields in DIB structure: bmh.w.dib.biSize = cbFixNum; bmh.w.dib.biCompression = 0L; bmh.w.dib.biSizeImage = 0L; // Determine size of bitmap header plus all data if (bmh.fCompressed) lcbBits = LAlignLong(bmh.w.dib.biWidth * bmh.w.dib.biBitCount) * bmh.w.dib.biHeight; else // +5 is a fudge factor for possible alignment ^ lcbBits = bmh.lcbSizeBits; hbmh = GhAlloc(GPTR, LcbSizeQbmh(&bmh) + lcbBits + bmh.lcbSizeExtra); if (!hbmh) return hbmhOOM; qbmh = (QBMH) PtrFromGh(hbmh); // Copy header and color table: MoveMemory(qbmh, &bmh, sizeof(BMH) - 2 * sizeof(RGBQUAD)); MoveMemory(qbmh->rgrgb, qv, sizeof(RGBQUAD) * bmh.w.dib.biClrUsed); // Copy bits, decompressing if necessary: qbmh->lcbOffsetBits = LcbSizeQbmh(qbmh); if (bmh.fCompressed == BMH_COMPRESS_30) { qbmh->lcbSizeBits = LcbUncompressHb(qbBase + bmh.lcbOffsetBits, QFromQCb(qbmh, qbmh->lcbOffsetBits), bmh.lcbSizeBits); ASSERT(qbmh->lcbSizeBits <= lcbBits); } else if (bmh.fCompressed == BMH_COMPRESS_ZECK) { qbmh->lcbSizeBits = LcbUncompressZeck( RFromRCb (qbBase, bmh.lcbOffsetBits), RFromRCb (qbmh, qbmh->lcbOffsetBits), bmh.lcbSizeBits); ASSERT(qbmh->lcbSizeBits <= lcbBits); } // New to WinHelp 4.0 // REVIEW: this has not been tested! else if (bmh.fCompressed == BMH_COMPRESS_RLE_ZECK) { DWORD cbBits; /* * We allocate as much memory as is needed to decompress the * Zeck block into the RLE block. The biYPelsPerMeter value is * used to save this information created by the help compiler. */ HGLOBAL gh = GhAlloc(GMEM_FIXED, bmh.w.dib.biYPelsPerMeter); bmh.w.dib.biYPelsPerMeter = 0; // First decompress Zeck cbBits = LcbUncompressZeck( RFromRCb(qbBase, bmh.lcbOffsetBits), PtrFromGh(gh), bmh.lcbSizeBits); // Now decompress RLE qbmh->lcbSizeBits = LcbUncompressHb(PtrFromGh(gh), RFromRCb(qbmh, qbmh->lcbOffsetBits), cbBits); FreeGh(gh); ASSERT(qbmh->lcbSizeBits <= lcbBits); } else MoveMemory(QFromQCb(qbmh, qbmh->lcbOffsetBits), qbBase + bmh.lcbOffsetBits, bmh.lcbSizeBits); qbmh->fCompressed = BMH_COMPRESS_NONE; // bits are no longer compressed // Copy extra info: qbmh->lcbOffsetExtra = qbmh->lcbOffsetBits + qbmh->lcbSizeBits; MoveMemory(RFromRCb (qbmh, qbmh->lcbOffsetExtra), RFromRCb (qbBase, bmh.lcbOffsetExtra), bmh.lcbSizeExtra); break; case bmWmetafile: #ifdef _X86_ qv = QVSkipQGA(qv, (&bmh.w.mf.mm)); bmh.w.mf.xExt = *(INT16 *) qv; qv = RFromRCb(qv, sizeof(INT16)); bmh.w.mf.yExt = *(INT16 *) qv; qv = RFromRCb(qv, sizeof(INT16)); qv = QVSkipQGB(qv, &lcbUncompressedBits); qv = QVSkipQGB(qv, (&bmh.lcbSizeBits)); qv = QVSkipQGB(qv, (&bmh.lcbSizeExtra)); bmh.lcbOffsetBits = *((DWORD *) qv); qv = RFromRCb(qv, sizeof(DWORD)); bmh.lcbOffsetExtra = *((DWORD *) qv); qv = RFromRCb(qv, sizeof(DWORD)); #else { SHORT shortTmp; qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GA, &shortTmp, qv)); bmh.w.mf.mm = shortTmp; qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_SHORT, &shortTmp, qv)); bmh.w.mf.xExt = shortTmp; qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_SHORT, &shortTmp, qv)); bmh.w.mf.yExt = shortTmp; } qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &lcbUncompressedBits, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.lcbSizeBits, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_GB, &bmh.lcbSizeExtra, qv)); qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_DWORD, &bmh.lcbOffsetBits, qv)) ; qv = RFromRCb( qv, LcbQuickMapSDFF(isdff, TE_DWORD, &bmh.lcbOffsetExtra, qv) ); #endif hbmh = GhAlloc(GPTR, sizeof(BMH) + bmh.lcbSizeExtra); if (hbmh == NULL) return hbmhOOM; qbmh = (QBMH) PtrFromGh(hbmh); *qbmh = bmh; qbmh->lcbOffsetExtra = sizeof( BMH ); MoveMemory(RFromRCb(qbmh, qbmh->lcbOffsetExtra), RFromRCb(qbBase, bmh.lcbOffsetExtra), bmh.lcbSizeExtra); qbmh->w.mf.hMF = HmfAlloc(LMEM_FIXED, lcbUncompressedBits); if (qbmh->w.mf.hMF == NULL) { FreeGh(hbmh); return hbmhOOM; } rbDest = (PBYTE) PtrFromGh(qbmh->w.mf.hMF); switch (bmh.fCompressed) { case BMH_COMPRESS_NONE: MoveMemory (rbDest, QFromQCb (qbBase, bmh.lcbOffsetBits), bmh.lcbSizeBits); break; case BMH_COMPRESS_30: LcbUncompressHb(qbBase + bmh.lcbOffsetBits, rbDest, bmh.lcbSizeBits); break; case BMH_COMPRESS_ZECK: LcbUncompressZeck(QFromQCb (qbBase, bmh.lcbOffsetBits), rbDest, bmh.lcbSizeBits); break; default: ASSERT(FALSE); break; } // Invalidate this field, as the bits are in a separate handle: qbmh->lcbOffsetBits = 0L; qbmh->lcbSizeBits = lcbUncompressedBits; qbmh->fCompressed = BMH_COMPRESS_NONE; break; default: return hbmhInvalid; } return hbmh; } /*************************************************************************** * - 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(HBMH hbmh) { QBMH qbmh; ASSERT(hbmh); qbmh = (QBMH) PtrFromGh(hbmh); // The bmh has not been discarded. if (qbmh->bmFormat == bmWmetafile && qbmh->lcbOffsetBits == 0L) { // Get rid of the current description of the metafile. if (qbmh->w.mf.hMF != NULL) FreeGh(qbmh->w.mf.hMF); } FreeGh(hbmh); } /*************************************************************************** * - Name LcbUncompressHb - * Purpose * Decompresses the bits in hbSrc. * * Arguments * hbSrc: Huge pointer to compressed bits. * hbDest: Buffer to copy decompressed bits to. * lcbSrc: Number of bytes in hbSrc. * * Returns * Number of bytes copied to hbDest. This can only be used for * real mode error checking, as the maximum size of hbDest must * be determined before decompression. * * +++ * * Notes * ***************************************************************************/ _section(runtime) LONG STDCALL LcbUncompressHb( hbSrc, hbDest, lcbSrc ) BYTE HUGE * hbSrc; BYTE HUGE * hbDest; LONG lcbSrc; { BYTE HUGE * hbStart; WORD cbRun; BYTE ch; hbStart = hbDest; while (lcbSrc-- > 0) { cbRun = *hbSrc++; if (cbRun & fRLEBit) { cbRun -= fRLEBit; lcbSrc -= cbRun; while (cbRun-- > 0) *hbDest++ = *hbSrc++; } else { ch = *hbSrc++; while (cbRun-- > 0) *hbDest++ = ch; lcbSrc--; } } return (hbDest - hbStart); } /*************************************************************************** * - Name LcbOldUncompressHb - * Purpose * This function is used only to decompress Help 2.5 bitmaps. * * Arguments * hbSrc: Huge pointer to source bits. * hbDest: Huge pointer to beginning of destination buffer. * lcbSrc: Number of compressed bytes in source. * lcbDest: Size of destination buffer. * * Returns * Actual number of bytes copied to destination buffer, or -1 if * buffer is too small. * * +++ * * Notes * ***************************************************************************/ _section(io) LONG STDCALL LcbOldUncompressHb( hbSrc, hbDest, lcbSrc, lcbDest ) BYTE HUGE * hbSrc; BYTE HUGE * hbDest; LONG lcbSrc; LONG lcbDest; { BYTE HUGE * hbStart; WORD cbRun; BYTE ch; /* Move pointers to the end of the buffers: */ hbSrc += lcbSrc; hbDest += lcbDest; hbStart = hbDest; while (lcbSrc-- > 0) { cbRun = *(--hbSrc); lcbDest -= (cbRun & ~fRLEBit); if (lcbDest < 0) return -1; if (cbRun & fRLEBit) { cbRun -= fRLEBit; lcbSrc -= cbRun; while (cbRun-- > 0) *(--hbDest) = *(--hbSrc); } else { ch = *(--hbSrc); while (cbRun-- > 0) *(--hbDest) = ch; lcbSrc--; } } return (hbStart - hbDest); } #if 0 /*************************************************************************** * - Name LcbCompressHb - * Purpose * Compresses bitmap bits using RLE. * * Arguments * hbSrc: Huge pointer to source bits. * hbDest: Huge pointer to destination bits. * lcbSrc: Number of bytes in source. * * Returns * Number of bytes in the destination. Guaranteed not to be * more than 128/127 times lcbSrc. * * +++ * * Notes * This function is used by bmconv, hc, and shed, but not by * winhelp. * Also, until LcbDiffHb is written to work correctly, this * function will not work in protect mode with bitmaps over 64K. * ***************************************************************************/ _section(io) LONG STDCALL LcbCompressHb( hbSrc, hbDest, lcbSrc ) BYTE HUGE * hbSrc; BYTE HUGE * hbDest; LONG lcbSrc; { BYTE HUGE * hbStart; LONG lcbRun, lcb; BYTE ch; hbStart = hbDest; while (lcbSrc > 0) { /* Find next run of dissimilar bytes: */ lcbRun = 0; if (lcbSrc <= 2) lcbRun = lcbSrc; else while ( hbSrc[lcbRun] != hbSrc[lcbRun + 1] || hbSrc[lcbRun] != hbSrc[lcbRun + 2] ) if (++lcbRun >= lcbSrc - 2) { lcbRun = lcbSrc; break; } lcbSrc -= lcbRun; // Output run of dissimilar bytes: while (lcbRun > 0) { lcb = min( lcbRun, cbMaxRun ); *hbDest++ = (BYTE) ((DWORD) lcb | fRLEBit); lcbRun -= lcb; while (lcb-- > 0) *hbDest++ = *hbSrc++; } if (lcbSrc == 0) break; /* Find next run of identical bytes: */ ch = *hbSrc; lcbRun = 1; while (lcbRun < lcbSrc && ch == hbSrc[lcbRun]) lcbRun++; lcbSrc -= lcbRun; hbSrc += lcbRun; /* Output run of identical bytes: */ while (lcbRun > 0) { lcb = min( lcbRun, cbMaxRun ); *hbDest++ = (BYTE) lcb; *hbDest++ = ch; lcbRun -= lcb; } } return LcbDiffHb( hbDest, hbStart ); } #endif