595 lines
15 KiB
C
595 lines
15 KiB
C
/*****************************************************************************
|
|
* *
|
|
* BMIO.C *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1989. *
|
|
* All Rights reserved. *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Module Intent *
|
|
* This module covers reading in bitmaps in various formats, and writing *
|
|
* them out in Help 3.0 format. *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Testing *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Current Owner: Larry Powelson *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Released by Development: (date) *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
#include "help.h"
|
|
#include "inc\_bitmap.h"
|
|
#include "inc\shed.h"
|
|
|
|
_subsystem(bitmap)
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Defines *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
/* Signature bytes at the beginning of a pagemaker metafile file.
|
|
*/
|
|
#define dwMFKey 0x9ac6cdd7
|
|
#define wMetafile (WORD) dwMFKey
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Typedefs *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
/* Old BITMAPCOREHEADER, minus bcSize field: */
|
|
typedef struct tagBITMAPOLDCOREHEADER
|
|
{
|
|
WORD bcWidth;
|
|
WORD bcHeight;
|
|
WORD bcPlanes;
|
|
WORD bcBitCount;
|
|
} BOCH;
|
|
|
|
/* Bitmap header from Help 2.5: */
|
|
typedef struct tagBITMAP25HEADER
|
|
{
|
|
WORD key1;
|
|
WORD key2;
|
|
WORD dxFile;
|
|
WORD dyFile;
|
|
WORD ScrAspectX;
|
|
WORD ScrAspectY;
|
|
WORD PrnAspectX;
|
|
WORD PrnAspectY;
|
|
WORD dxPrinter;
|
|
WORD dyPrinter;
|
|
WORD AspCorX;
|
|
WORD AspCorY;
|
|
WORD wCheck;
|
|
WORD res1;
|
|
WORD res2;
|
|
WORD res3;
|
|
} BITMAP25HEADER;
|
|
|
|
// this is a pagemaker compatible metafile format header
|
|
typedef struct tagMFH {
|
|
DWORD dwKey; // must be 0x9AC6CDD7
|
|
WORD hMF; // handle to metafile
|
|
RECT rcBound; // bounding rectangle
|
|
WORD wUnitsPerInch; // units per inch
|
|
DWORD dwReserved; // reserved - must be zero
|
|
WORD wChecksum; // checksum of previous 10
|
|
// words (XOR'd)
|
|
} MFH, *LPMFH;
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Static Variables *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
/* Default aspect ratios */
|
|
int cxAspectDefault = cxAspectVGA;
|
|
int cyAspectDefault = cyAspectVGA;
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Prototypes *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
HBMH STDCALL HbmhReadDibFid( FID );
|
|
HBMH STDCALL HbmhReadHelp25Fid( FID );
|
|
HBMH STDCALL HbmhReadPMMetafileFid( FID );
|
|
WORD STDCALL WCalcChecksum (LPMFH lpmfh);
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: HbmhReadHelp30Fid
|
|
- HbmhReadDibFid
|
|
- HbmhReadHelp25Fid
|
|
- HbmhReadPMMetafileFid
|
|
-
|
|
* Purpose:
|
|
* These four functions read in bitmaps of various formats and
|
|
* return them in Help 3.0 memory format. (PMMetafile is PageMaker
|
|
* metafile format.)
|
|
*
|
|
* Arguments:
|
|
* fid -- file handle of file being read.
|
|
* pibmh -- Pointer to bitmap in bitmap group to read (Help30 only).
|
|
*
|
|
* Returns:
|
|
* hbmh of bitmap read. hbmhInvalid for bogus bitmap, hbmhOOM for
|
|
* out of memory.
|
|
* If *pibmh = 0, then *pibmh will be set to the number of bitmaps
|
|
* that are in that bitmap file. Otherwise, it will be unaffected.
|
|
* (Help30 only).
|
|
*
|
|
***************************************************************************/
|
|
|
|
HBMH STDCALL HbmhReadHelp30Fid(FID fid, PI pibmh)
|
|
{
|
|
LH lhbgh;
|
|
BGH * pbgh;
|
|
LONG lcb;
|
|
HBMH hbmh;
|
|
QV qv;
|
|
|
|
lcb = sizeof( BGH ) + ( ( *pibmh + 1 ) * sizeof( DWORD ) );
|
|
lhbgh = LhAlloc(LMEM_FIXED, (WORD) lcb );
|
|
if ( lhbgh == NULL )
|
|
return hbmhOOM;
|
|
pbgh = PtrFromGh( lhbgh );
|
|
ASSERT( pbgh != NULL );
|
|
|
|
LSeekFid( fid, 0L, SEEK_SET );
|
|
if (LcbReadFid(fid, pbgh, lcb) != lcb) {
|
|
FreeLh(lhbgh);
|
|
return hbmhInvalid;
|
|
}
|
|
|
|
ASSERT(*pibmh < pbgh->cbmhMac);
|
|
|
|
if (*pibmh == pbgh->cbmhMac - 1)
|
|
lcb = LSeekFid(fid, 0L, SEEK_END) - pbgh->rglcbBmh[ *pibmh ];
|
|
else
|
|
lcb = pbgh->rglcbBmh[*pibmh + 1] - pbgh->rglcbBmh[*pibmh];
|
|
|
|
qv = (void*) LhAlloc(LMEM_FIXED, lcb);
|
|
if (!qv) {
|
|
FreeLh(lhbgh);
|
|
return hbmhOOM;
|
|
}
|
|
|
|
LSeekFid(fid, pbgh->rglcbBmh[*pibmh ], SEEK_SET);
|
|
if (LcbReadFid(fid, qv, lcb) != lcb)
|
|
hbmh = hbmhInvalid;
|
|
else
|
|
#ifdef _X86_
|
|
hbmh = HbmhExpandQv(qv);
|
|
#else // _X86_
|
|
{
|
|
SDFF_FILEID isdff;
|
|
|
|
/* If this is ever called on a MAC, the file flag will need
|
|
* to be changed to BIGENDIAN.
|
|
*/
|
|
#ifdef MAC
|
|
isdff = IRegisterFileSDFF( SDFF_FILEFLAGS_BIGENDIAN, NULL );
|
|
#else // MAC
|
|
isdff = IRegisterFileSDFF( SDFF_FILEFLAGS_LITTLEENDIAN, NULL );
|
|
#endif // else MAC
|
|
hbmh = HbmhExpandQv( qv, isdff );
|
|
IDiscardFileSDFF( isdff );
|
|
}
|
|
#endif // else _X86_
|
|
FreeLh(qv);
|
|
|
|
if (*pibmh == 0)
|
|
*pibmh = pbgh->cbmhMac;
|
|
|
|
FreeLh(lhbgh);
|
|
|
|
return hbmh;
|
|
}
|
|
|
|
|
|
HBMH STDCALL HbmhReadDibFid(FID fid)
|
|
{
|
|
BITMAPFILEHEADER bfh;
|
|
BOCH boch;
|
|
BMH bmh;
|
|
HBMH hbmh;
|
|
RBMH rbmh;
|
|
LONG lcb;
|
|
int iColors;
|
|
DWORD cbFix;
|
|
|
|
lcb = LSeekFid(fid, 0L, SEEK_END);
|
|
LSeekFid(fid, 0L, SEEK_SET);
|
|
LcbReadFid(fid, &bfh, sizeof(BITMAPFILEHEADER));
|
|
lcb -= bfh.bfOffBits;
|
|
|
|
LcbReadFid(fid, &cbFix, sizeof(DWORD));
|
|
switch ((WORD) cbFix) {
|
|
case cbOldFixNum:
|
|
if (LcbReadFid(fid, &boch, sizeof(BOCH)) != sizeof(BOCH))
|
|
return hbmhInvalid;
|
|
|
|
if (boch.bcBitCount != 24)
|
|
bmh.w.dib.biClrUsed = 1 << boch.bcBitCount;
|
|
else
|
|
bmh.w.dib.biClrUsed = 0;
|
|
|
|
hbmh = GhAlloc(GPTR, LcbSizeQbmh(&bmh) + lcb);
|
|
|
|
if (hbmh == NULL)
|
|
return hbmhOOM;
|
|
|
|
rbmh = PtrFromGh(hbmh);
|
|
|
|
for (iColors = 0; iColors < (int) bmh.w.dib.biClrUsed; ++iColors)
|
|
LcbReadFid(fid, &rbmh->rgrgb[iColors], sizeof(RGBTRIPLE));
|
|
|
|
// We require zerod memory for some of these fields
|
|
|
|
rbmh->w.dib.biSize = cbFixNum;
|
|
rbmh->w.dib.biWidth = (DWORD) boch.bcWidth;
|
|
rbmh->w.dib.biHeight = (DWORD) boch.bcHeight;
|
|
rbmh->w.dib.biPlanes = boch.bcPlanes;
|
|
rbmh->w.dib.biBitCount = boch.bcBitCount;
|
|
rbmh->w.dib.biXPelsPerMeter = cxAspectDefault;
|
|
rbmh->w.dib.biYPelsPerMeter = cyAspectDefault;
|
|
rbmh->w.dib.biClrUsed = bmh.w.dib.biClrUsed;
|
|
break;
|
|
|
|
case cbFixNum:
|
|
if (LcbReadFid( fid, &bmh.w.dib.biWidth,
|
|
(LONG) (cbFixNum - sizeof( DWORD )))
|
|
!= (LONG) (cbFixNum - sizeof( DWORD )))
|
|
return hbmhInvalid;
|
|
|
|
// We do not support compressed DIBs
|
|
|
|
// REVIEW: why not?
|
|
|
|
if (bmh.w.dib.biCompression != 0L)
|
|
return hbmhInvalid;
|
|
|
|
/*
|
|
* DIB aspect ratios are pels per meter, while hc bitmaps are
|
|
* actually pels per inch.
|
|
*/
|
|
|
|
bmh.w.dib.biXPelsPerMeter =
|
|
MulDiv(bmh.w.dib.biXPelsPerMeter, 100, 3937);
|
|
bmh.w.dib.biYPelsPerMeter =
|
|
MulDiv(bmh.w.dib.biYPelsPerMeter, 100, 3937);
|
|
|
|
if (bmh.w.dib.biClrUsed == 0 && bmh.w.dib.biBitCount != 24)
|
|
bmh.w.dib.biClrUsed = 1 << bmh.w.dib.biBitCount;
|
|
|
|
hbmh = GhAlloc(GPTR, LcbSizeQbmh(&bmh) + lcb);
|
|
if (hbmh == NULL)
|
|
return hbmhOOM;
|
|
|
|
rbmh = PtrFromGh(hbmh);
|
|
*rbmh = bmh;
|
|
LcbReadFid(fid, rbmh->rgrgb,
|
|
sizeof(RGBQUAD) * rbmh->w.dib.biClrUsed);
|
|
|
|
if (rbmh->w.dib.biXPelsPerMeter == 0 ||
|
|
rbmh->w.dib.biYPelsPerMeter == 0) {
|
|
rbmh->w.dib.biXPelsPerMeter = cxAspectDefault;
|
|
rbmh->w.dib.biYPelsPerMeter = cyAspectDefault;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return hbmhInvalid;
|
|
}
|
|
|
|
rbmh->bmFormat = bmDIB;
|
|
rbmh->lcbOffsetBits = LcbSizeQbmh( rbmh );
|
|
rbmh->lcbSizeBits = lcb;
|
|
rbmh->w.dib.biSize = cbFixNum;
|
|
LSeekFid(fid, bfh.bfOffBits, SEEK_SET);
|
|
if (LcbReadFid(fid, QFromQCb(rbmh, rbmh->lcbOffsetBits), lcb)
|
|
!= lcb) {
|
|
FreeGh( hbmh );
|
|
return hbmhInvalid;
|
|
}
|
|
return hbmh;
|
|
}
|
|
|
|
HBMH STDCALL HbmhReadHelp25Fid(FID fid)
|
|
{
|
|
BITMAP25HEADER bm25h;
|
|
HBMH hbmh;
|
|
RBMH rbmh;
|
|
RB rBits;
|
|
GH hBits;
|
|
LONG lcbBits, lcbDest;
|
|
|
|
LSeekFid(fid, 0L, SEEK_SET);
|
|
if (LcbReadFid( fid, &bm25h, (LONG)sizeof( BITMAP25HEADER ))
|
|
!= (LONG)sizeof( BITMAP25HEADER ) || bm25h.key2 != wBitmapVersion25b)
|
|
return hbmhInvalid;
|
|
|
|
lcbBits = bm25h.dyFile * ((bm25h.dxFile + 15) / 16) * 2;
|
|
hbmh = GhAlloc(GPTR, sizeof( BMH ) + lcbBits );
|
|
if (hbmh == NULL)
|
|
return hbmhOOM;
|
|
|
|
// We require zerod memory for some of these fields.
|
|
|
|
rbmh = PtrFromGh(hbmh);
|
|
rbmh->bmFormat = bmWbitmap;
|
|
rbmh->fCompressed = BMH_COMPRESS_NONE;
|
|
rbmh->lcbSizeBits = lcbBits;
|
|
rbmh->lcbOffsetBits = LcbSizeQbmh( rbmh );
|
|
rbmh->w.dib.biSize = cbFixNum;
|
|
rbmh->w.dib.biWidth = bm25h.dxFile;
|
|
rbmh->w.dib.biHeight = bm25h.dyFile;
|
|
rbmh->w.dib.biPlanes = 1;
|
|
rbmh->w.dib.biBitCount = 1;
|
|
rbmh->w.dib.biXPelsPerMeter = cxAspectDefault;
|
|
rbmh->w.dib.biYPelsPerMeter = cyAspectDefault;
|
|
|
|
hBits = GhAlloc(GPTR, (LONG) bm25h.res1);
|
|
if (hBits == NULL) {
|
|
FreeGh(hbmh);
|
|
return hbmhInvalid;
|
|
}
|
|
rBits = PtrFromGh(hBits);
|
|
LcbReadFid(fid, rBits, (LONG) bm25h.res1);
|
|
lcbDest = LcbOldUncompressHb(rBits,
|
|
QFromQCb(rbmh, rbmh->lcbOffsetBits), (LONG) bm25h.res1, lcbBits);
|
|
|
|
// Fix up offset if decompression didn't completely fill buffer
|
|
|
|
rbmh->lcbOffsetBits += (lcbBits - lcbDest);
|
|
|
|
FreeGh( hBits );
|
|
|
|
// Check for failed decompression
|
|
|
|
if (lcbDest == -1) {
|
|
FreeGh( hbmh );
|
|
return hbmhInvalid;
|
|
}
|
|
|
|
return hbmh;
|
|
}
|
|
|
|
HBMH STDCALL HbmhReadPMMetafileFid(FID fid)
|
|
{
|
|
HANDLE hMF;
|
|
LPSTR lpMF;
|
|
MFH mfh;
|
|
LONG lcbData;
|
|
HBMH hbmh;
|
|
QBMH qbmh;
|
|
|
|
lcbData = LSeekFid(fid, 0, SEEK_END) - sizeof (MFH);
|
|
LSeekFid(fid, 0, SEEK_SET);
|
|
|
|
if (LcbReadFid(fid, &mfh, sizeof(MFH)) != sizeof(MFH))
|
|
return hbmhInvalid;
|
|
|
|
// is the key correct
|
|
if (mfh.dwKey != dwMFKey)
|
|
return hbmhInvalid;
|
|
|
|
if (!(hMF = LhAlloc(LMEM_FIXED, lcbData)))
|
|
return hbmhOOM;
|
|
lpMF = PtrFromGh(hMF);
|
|
|
|
if (LcbReadFid(fid, lpMF, lcbData) != lcbData)
|
|
return hbmhInvalid;
|
|
|
|
if (!(hbmh = GhAlloc (GPTR, sizeof (BMH)))) {
|
|
FreeHmf(hMF);
|
|
return hbmhOOM;
|
|
}
|
|
|
|
qbmh = PtrFromGh(hbmh);
|
|
|
|
// We require zerod memory for some of these fields.
|
|
|
|
qbmh->bmFormat = bmWmetafile;
|
|
qbmh->lcbSizeBits = lcbData;
|
|
qbmh->w.mf.mm = MM_ANISOTROPIC;
|
|
qbmh->w.mf.xExt =
|
|
MulDiv (mfh.rcBound.right - mfh.rcBound.left, 2540, mfh.wUnitsPerInch);
|
|
qbmh->w.mf.yExt =
|
|
MulDiv (mfh.rcBound.bottom - mfh.rcBound.top, 2540, mfh.wUnitsPerInch);
|
|
qbmh->w.mf.hMF = hMF;
|
|
|
|
return hbmh;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HbmhReadFid
|
|
-
|
|
* Purpose
|
|
* Reads in a file containing a Windows resource, DIB, or Help 2.5
|
|
* bitmap, and converts it to Help 3.0 format.
|
|
*
|
|
* Arguments
|
|
* fid: DOS file handle.
|
|
*
|
|
* Returns
|
|
* A huge global handle to the bitmap, in 3.0 format. Returns hbmhInvalid if
|
|
* the file is not an accepted bitmap format. Returns hbmh30 if the bitmap
|
|
* is in Help 3.0 format. Returns hbmhOOM on out of memory.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* If the bitmap does not contain aspect ratio information, then
|
|
* the values in the globals cxAspectDefault and cyAspectDefault
|
|
* are used.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#pragma warning(disable:4309) // 'cast' : truncation of constant value
|
|
|
|
HBMH STDCALL HbmhReadFid( FID fid )
|
|
{
|
|
BMPH bmph;
|
|
RBMH rbmh;
|
|
LONG lcbBits;
|
|
HBMH hbmh;
|
|
|
|
// Note that no file header structure is smaller than a BMPH
|
|
|
|
if (LcbReadFid( fid, &bmph, sizeof( BMPH )) != sizeof( BMPH ))
|
|
return hbmhInvalid;
|
|
|
|
if (bmph.bVersion != bBmp) {
|
|
switch (*((WORD *) &bmph.bVersion)) {
|
|
case wBitmapVersion2:
|
|
case wBitmapVersion3:
|
|
return hbmh30;
|
|
|
|
case wDIB:
|
|
return HbmhReadDibFid(fid);
|
|
|
|
case wBitmapVersion25a:
|
|
return HbmhReadHelp25Fid(fid);
|
|
|
|
case wMetafile:
|
|
return HbmhReadPMMetafileFid(fid);
|
|
|
|
default:
|
|
return hbmhInvalid;
|
|
}
|
|
} // (bmph.bVersion != bBmp)
|
|
|
|
lcbBits = bmph.cbWidthBytes * bmph.cHeight * bmph.cPlanes;
|
|
hbmh = GhAlloc(GPTR, sizeof(BMH) + lcbBits);
|
|
if (hbmh == NULL)
|
|
return hbmhOOM;
|
|
|
|
// We require zerod memory for some of these fields
|
|
|
|
rbmh = PtrFromGh(hbmh);
|
|
rbmh->bmFormat = bmWbitmap;
|
|
rbmh->lcbSizeBits = lcbBits;
|
|
rbmh->lcbOffsetBits = LcbSizeQbmh(rbmh);
|
|
rbmh->w.dib.biSize = cbFixNum;
|
|
rbmh->w.dib.biWidth = bmph.cWidth;
|
|
rbmh->w.dib.biHeight = bmph.cHeight;
|
|
rbmh->w.dib.biPlanes = bmph.cPlanes;
|
|
rbmh->w.dib.biBitCount = bmph.cBitCount;
|
|
rbmh->w.dib.biXPelsPerMeter = cxAspectDefault;
|
|
rbmh->w.dib.biYPelsPerMeter = cyAspectDefault;
|
|
if (LcbReadFid(fid, QFromQCb(rbmh, rbmh->lcbOffsetBits), lcbBits)
|
|
!= lcbBits) {
|
|
FreeGh( hbmh );
|
|
return hbmhInvalid;
|
|
}
|
|
return hbmh;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FEnumHotspotsLphsh
|
|
-
|
|
* Purpose:
|
|
* This function enumerates the hotspots in lphsh.
|
|
*
|
|
* Arguments:
|
|
* lphsh: Pointer to SHED header information.
|
|
* lcbData: Total size of hotspot information.
|
|
* pfnLphs: Callback function for hotspot processing.
|
|
* hData: Handle to information to be passed to callback function.
|
|
*
|
|
* Returns:
|
|
* TRUE if data is valid, FALSE otherwise.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
* lphsh points to data that can cross a 64K boundary at any
|
|
* time, including in the middle of structures.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL FEnumHotspotsLphsh(LPHSH lphsh, LONG lcbData, PFNLPHS pfnLphs,
|
|
HANDLE hData)
|
|
{
|
|
HSH hsh;
|
|
HS hs;
|
|
MBHS mbhs, HUGE * rmbhs;
|
|
RB rbData;
|
|
WORD iHotspot, cbT;
|
|
|
|
if (lphsh->bHotspotVersion != bHotspotVersion1)
|
|
return FALSE;
|
|
|
|
MoveMemory(&hsh, lphsh, sizeof(HSH));
|
|
rmbhs = RFromRCb(lphsh, sizeof(HSH));
|
|
|
|
// Point rbData to SHED data
|
|
|
|
rbData = RFromRCb(rmbhs, hsh.wcHotspots * sizeof(MBHS) +
|
|
lphsh->lcbData);
|
|
|
|
// Set lcbData to just the size of the SHED data
|
|
|
|
lcbData -= (rbData - (RB) lphsh); // REVIEW: Huge pointer difference
|
|
|
|
for (iHotspot = 0; iHotspot < hsh.wcHotspots; ++iHotspot) {
|
|
MoveMemory(&mbhs, rmbhs, sizeof(MBHS));
|
|
|
|
/* Clever HACK: We set hs.bBindType to 0 here so that the
|
|
* string length functions are guaranteed to terminate.
|
|
*/
|
|
hs.bBindType = 0;
|
|
|
|
// Copy hotspot name
|
|
|
|
MoveMemory(hs.szHotspotName, rbData,
|
|
(size_t) min((LONG) cbMaxHotspotName, lcbData));
|
|
cbT = strlen( hs.szHotspotName ) + 1;
|
|
if ( (LONG) cbT > lcbData )
|
|
return FALSE;
|
|
rbData += cbT;
|
|
lcbData -= cbT;
|
|
|
|
// Copy binding string
|
|
|
|
MoveMemory(hs.szBinding, rbData,
|
|
(size_t) min((LONG) cbMaxBinding, lcbData));
|
|
cbT = strlen( hs.szBinding ) + 1;
|
|
if ( (LONG) cbT > lcbData )
|
|
return FALSE;
|
|
rbData += cbT;
|
|
lcbData -= cbT;
|
|
|
|
hs.bBindType = mbhs.bType;
|
|
hs.bAttributes = mbhs.bAttributes;
|
|
hs.rect.left = mbhs.xPos;
|
|
hs.rect.top = mbhs.yPos;
|
|
hs.rect.right = mbhs.xPos + mbhs.dxSize;
|
|
hs.rect.bottom = mbhs.yPos + mbhs.dySize;
|
|
|
|
(*pfnLphs) (&hs, hData);
|
|
|
|
rmbhs = RFromRCb(rmbhs, sizeof(MBHS));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|