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.
828 lines
20 KiB
828 lines
20 KiB
/****************************************************************************
|
|
* *
|
|
* CBM.C *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1990. *
|
|
* All Rights reserved. *
|
|
* *
|
|
*****************************************************************************
|
|
* *
|
|
* Module Intent *
|
|
* This module processes embedded commands in the RTF text which are *
|
|
* to be interpreted in a non-WYSIWYG fashion, as special "help" commands *
|
|
* such as wrapped bitmaps and embedded windows. *
|
|
* For historical reasons only, this module also contains the code for *
|
|
* managing bitmaps inserted visually. *
|
|
* *
|
|
****************************************************************************/
|
|
#include "stdafx.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "mciwnd.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
const char WINHELP_WINDOW_FLAG = '!';
|
|
const char MCI_WINDOW_FLAG = '*';
|
|
|
|
/****************************************************************************
|
|
* *
|
|
* Defines *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
// HACK -- see comment in FProcCbmSz()
|
|
|
|
#define fInlineFlag 0x40
|
|
|
|
/* This macro fills the given string with the name to use for that
|
|
* bitmap number in the file system.
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Typedefs *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
// Embedded window construct
|
|
|
|
typedef struct {
|
|
INT16 wStyle;
|
|
INT16 dx;
|
|
INT16 dy;
|
|
} EWCONST, *QEWCONST;
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Prototypes *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
static RC_TYPE STDCALL RcWritePbitmap(RTF_BITMAP * pbitmap, ART art, HF hf);
|
|
static void STDCALL CallbackLphs(HS*, HANDLE);
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Static Variables *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name FProcCbmSz
|
|
-
|
|
* Purpose
|
|
* This function interprets the given string as a bitmap by reference,
|
|
* and outputs a bitmap command to the current FCP.
|
|
*
|
|
* Arguments
|
|
* PSTR szBitmap: Name of bitmap.
|
|
* BYTE bType: Indicates whether the bitmap is inline or wrapped.
|
|
* BOOL fOutput: TRUE if bitmap command needs to be output.
|
|
*
|
|
* Returns
|
|
* TRUE if the string is indeed a bitmap by reference, FALSE if
|
|
* it is not.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* This function currently uses the global state machine concept
|
|
* and can cause an FCP to be output as well as the current bitmap
|
|
* command. This should change by replacing fOutput with phpj,
|
|
* which may be nil.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL FProcCbmSz(PSTR pszBitmap, BYTE bType, BOOL fOutput)
|
|
{
|
|
QOBM qobm;
|
|
int lcbSize;
|
|
BOOL fTransparent;
|
|
|
|
switch (bType) {
|
|
case CMD_TEXTBMP_INLINE:
|
|
bType = CMD_INLINE_OBJ;
|
|
fTransparent = TRUE;
|
|
break;
|
|
|
|
case CMD_TEXTBMP_LEFT:
|
|
bType = CMD_WRAP_LEFT;
|
|
fTransparent = TRUE;
|
|
break;
|
|
|
|
case CMD_TEXTBMP_RIGHT:
|
|
bType = CMD_WRAP_RIGHT;
|
|
fTransparent = TRUE;
|
|
break;
|
|
|
|
default:
|
|
fTransparent = FALSE;
|
|
}
|
|
|
|
// save the bitmap
|
|
|
|
if (fOutput) {
|
|
MOBJ mobjTemp;
|
|
UINT cbMobj;
|
|
char rgchBuf[sizeof(MOBJ)];
|
|
int iBitmap;
|
|
UINT wObjrgT;
|
|
LBM* qlbm;
|
|
|
|
SzTrimSz(pszBitmap);
|
|
RC_TYPE rc = AddBitmap(pszBitmap, &iBitmap, TRUE, fTransparent);
|
|
|
|
if (rc != RC_Success && rc != RC_DuplicateBitmap)
|
|
return TRUE;
|
|
|
|
if (iBitmap != -1) {
|
|
qlbm = (LBM*) pdrgBitmaps->GetPtr(iBitmap);
|
|
ASSERT(!qlbm->wObjrg);
|
|
if (qlbm->fError)
|
|
iBitmap = -1;
|
|
else if (rc != RC_DuplicateBitmap)
|
|
CountObjects(qlbm); // fill in the number of objects
|
|
}
|
|
|
|
qobm = (QOBM) lcCalloc(sizeof(OBM));
|
|
|
|
qobm->fInline = FALSE;
|
|
qobm->cBitmap = iBitmap;
|
|
lcbSize = sizeof(OBM);
|
|
|
|
mobjTemp.bType = (BYTE) FCTYPE_BITMAP_COUNT;
|
|
mobjTemp.wObjInfo = 1 + (iBitmap == -1 ? 0 : qlbm->wObjrg);
|
|
wObjrgT = mobjTemp.wObjInfo;
|
|
mobjTemp.lcbSize = lcbSize;
|
|
cbMobj = CbPackMOBJ(&mobjTemp, rgchBuf);
|
|
|
|
if (RcOutputCommand(bType, rgchBuf, cbMobj, TRUE) == RC_Success)
|
|
pbfCommand->Add(qobm, (UINT) lcbSize);
|
|
|
|
lcFree(qobm);
|
|
|
|
/*
|
|
* Increment adrs AFTER possibly writing out previous
|
|
* FCP.
|
|
*/
|
|
|
|
adrs.wObjrg += wObjrgT;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: FProcEwSz
|
|
|
|
PURPOSE: Parses an embedded window command.
|
|
|
|
PARAMETERS:
|
|
pszEw string containing embedded window arguments.
|
|
bType Type of embedded window command.
|
|
fOutput TRUE if EW command is to be written out to globals everywhere.
|
|
|
|
RETURNS: TRUE if successful, FALSE if syntax is not correct.
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
09-Apr-1994 [ralphw]
|
|
This is also use to support the {button and {mci commands which
|
|
are converted into a special case of an embedded window that
|
|
WinHelp 4.0 and later understands.
|
|
|
|
***************************************************************************/
|
|
|
|
// Constants taken from mmio.c in winhelp\src\winpmlyr
|
|
|
|
#define MCI_CMD_NOTHING (0)
|
|
#define MCI_CMD_REPEAT (1 << 0)
|
|
#define MCI_CMD_PLAY (1 << 1)
|
|
|
|
const SZCONVERT MCIFlags[] = {
|
|
"NOPLAYBAR", MCIWNDF_NOPLAYBAR,
|
|
"NOMENU", MCIWNDF_NOMENU,
|
|
|
|
"", 0
|
|
};
|
|
|
|
const SZCONVERT MCICmds[] = {
|
|
"REPEAT", MCI_CMD_REPEAT,
|
|
"PLAY", MCI_CMD_PLAY,
|
|
|
|
"", 0
|
|
};
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
static const char txtExternal[] = "EXTERNAL";
|
|
#pragma data_seg()
|
|
|
|
BOOL STDCALL FProcEwSz(PSTR pszEw, BYTE bType, BOOL fOutput)
|
|
{
|
|
EWCONST ewconst;
|
|
PSTR pszDeltas;
|
|
int cCommas;
|
|
|
|
// Is this an authorable button?
|
|
|
|
if (bType == CMD_BUTTON || bType == CMD_BUTTON_LEFT ||
|
|
bType == CMD_BUTTON_RIGHT) { // authorable button
|
|
PSTR psz = StrChr(pszEw, ',', fDBCSSystem);
|
|
if (!psz) {
|
|
VReportError(HCERR_MISSING_COMMA, &errHpj, pszEw);
|
|
return FALSE;
|
|
}
|
|
if (psz[1] == ' ')
|
|
strcpy(psz + 1, FirstNonSpace(psz + 2, fDBCSSystem));
|
|
|
|
// Parse the macro, but continue even if its invalid
|
|
|
|
if (Execute(psz + 1) == wMACRO_EXPANSION)
|
|
strcpy(psz + 1, GetMacroExpansion()); // lord help us if psz overflows...
|
|
|
|
/*
|
|
* Sneaky hack time -- pszEw points to scratchbuf + sizeof
|
|
* command. We need to precede the button text with a '!' character
|
|
* to indicate to WinHelp that this is an authorable button, so we
|
|
* back up our pointer in scratchbuf and overwrite part of the
|
|
* original command (which we no longer need).
|
|
*/
|
|
|
|
pszEw--;
|
|
pszEw[0] = WINHELP_WINDOW_FLAG;
|
|
|
|
// Convert button command to embedded window command
|
|
|
|
if (bType == CMD_BUTTON_LEFT)
|
|
bType = CMD_WRAP_LEFT;
|
|
else if (bType == CMD_BUTTON_RIGHT)
|
|
bType = CMD_WRAP_RIGHT;
|
|
else
|
|
bType = CMD_INLINE_OBJ;
|
|
|
|
if (fOutput) {
|
|
MOBJ mobjTemp;
|
|
char szBuf[sizeof(MOBJ)];
|
|
RC_TYPE rc;
|
|
|
|
int cbString = strlen(pszEw) + 1;
|
|
int cbEWCmd = sizeof(EWCONST) + cbString;
|
|
|
|
mobjTemp.bType = (BYTE) FCTYPE_WINDOW;
|
|
mobjTemp.lcbSize = cbEWCmd; // exclude object size
|
|
int cbCOBJ = CbPackMOBJ(&mobjTemp, szBuf);
|
|
|
|
/*
|
|
* RcOutputCommand() can trash szScratchBuf which is what
|
|
* pszEw points to, so we need to save it here.
|
|
*/
|
|
|
|
CStr cszEw(pszEw);
|
|
rc = RcOutputCommand(bType, szBuf, cbCOBJ, TRUE);
|
|
|
|
// REVIEW: so how about reporting the error conditions? 05-Sep-1993 [ralphw]
|
|
|
|
if (rc == RC_Success) {
|
|
pbfCommand->Add(&ewconst, sizeof(EWCONST));
|
|
return pbfCommand->Add(cszEw, cbString);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Is this an MCI command?
|
|
|
|
else if (bType == CMD_MCI || bType == CMD_MCI_LEFT ||
|
|
bType == CMD_MCI_RIGHT) { // authorable MCI
|
|
|
|
CMem mem(256);
|
|
|
|
// Set default flags and commands for MCI window
|
|
|
|
DWORD flags = MCIWNDF_NOOPEN | MCIWNDF_NOTIFYSIZE;
|
|
DWORD cmds = MCI_CMD_NOTHING;
|
|
BOOL fExternal = FALSE;
|
|
|
|
PSTR psz = StrChr(pszEw, ',', fDBCSSystem);
|
|
if (psz) { // if we have a comma, then we have flags
|
|
*psz = '\0';
|
|
psz = FirstNonSpace(psz + 1, fDBCSSystem); // point to the text after the comma
|
|
PSTR pszBuf = (PSTR) mem.pb;
|
|
|
|
PSTR pszTmp = FirstNonSpace(pszEw, fDBCSSystem);
|
|
for (;;) {
|
|
pszTmp = GetArg(pszBuf, pszTmp);
|
|
if (!*pszBuf)
|
|
break;
|
|
|
|
int i;
|
|
|
|
// Is it a flag value?
|
|
|
|
if (_stricmp(pszBuf, (LPCSTR)txtExternal) == 0) {
|
|
fExternal = TRUE;
|
|
continue;
|
|
}
|
|
for (i = 0; MCIFlags[i].psz[0]; i++) {
|
|
if (_stricmp(pszBuf, MCIFlags[i].psz) == 0) {
|
|
flags |= MCIFlags[i].value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!MCIFlags[i].psz[0]) {
|
|
|
|
// Not a flag, so check for a command
|
|
|
|
for (i = 0; MCICmds[i].psz[0]; i++) {
|
|
if (_stricmp(pszBuf, MCICmds[i].psz) == 0) {
|
|
cmds |= MCICmds[i].value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!pszTmp || !*pszTmp)
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
psz = FirstNonSpace(pszEw, fDBCSSystem);
|
|
|
|
// The format for MCI is: helpfile.hlp+mci_file
|
|
|
|
char szTmpFile[MAX_PATH];
|
|
FM fm;
|
|
if (!fExternal) {
|
|
fm = FmNew(szHlpFile);
|
|
SzPartsFm(fm, szTmpFile, PARTBASE);
|
|
strcat(szTmpFile, "+");
|
|
DisposeFm(fm);
|
|
|
|
// Now add the MCI filename as it will appear in the internal file system
|
|
|
|
fm = FmNew(psz);
|
|
SzPartsFm(fm, szTmpFile + strlen(szTmpFile), PARTBASE);
|
|
}
|
|
else
|
|
strcpy(szTmpFile, psz);
|
|
|
|
pszEw = (PSTR) mem.pb;
|
|
*pszEw = MCI_WINDOW_FLAG;
|
|
_ultoa(flags, pszEw + 1, 10);
|
|
strcat(pszEw, ",");
|
|
_ultoa(cmds, pszEw + strlen(pszEw), 10);
|
|
strcat(pszEw, ",");
|
|
strcat(pszEw, szTmpFile);
|
|
|
|
if (!fExternal) {
|
|
if (fOutput)
|
|
RcParseBaggageSz(fm);
|
|
DisposeFm(fm);
|
|
}
|
|
|
|
// REVIEW: 09-Apr-1994 [ralphw] Is there any way to get the AVI
|
|
// file size here and thereby pass the window size?
|
|
|
|
// Convert button command to embedded window command
|
|
|
|
if (bType == CMD_MCI_LEFT)
|
|
bType = CMD_WRAP_LEFT;
|
|
else if (bType == CMD_MCI_RIGHT)
|
|
bType = CMD_WRAP_RIGHT;
|
|
else
|
|
bType = CMD_INLINE_OBJ;
|
|
|
|
if (fOutput) {
|
|
MOBJ mobjTemp;
|
|
char szBuf[sizeof(MOBJ)];
|
|
RC_TYPE rc;
|
|
|
|
int cbString = strlen(pszEw) + 1;
|
|
int cbEWCmd = sizeof(EWCONST) + cbString;
|
|
|
|
mobjTemp.bType = (BYTE) FCTYPE_WINDOW;
|
|
mobjTemp.lcbSize = cbEWCmd; // exclude object size
|
|
int cbCOBJ = CbPackMOBJ(&mobjTemp, szBuf);
|
|
rc = RcOutputCommand(bType, szBuf, cbCOBJ, TRUE);
|
|
|
|
// REVIEW: so how about reporting the error conditions? 05-Sep-1993 [ralphw]
|
|
|
|
if (rc == RC_Success) {
|
|
pbfCommand->Add(&ewconst, sizeof(EWCONST));
|
|
return pbfCommand->Add(pszEw, cbString);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Syntax is ewl modulename, classname, data, dx, dy. Modulename,
|
|
* classname, and data get output as a single string and parsed at
|
|
* runtime. Dx and dy are optional, and parsed here and put into to
|
|
* ewconst structure.
|
|
*/
|
|
|
|
for (pszDeltas = pszEw, cCommas = 0;
|
|
*pszDeltas != '\0' && cCommas < 3;
|
|
++pszDeltas) {
|
|
if (*pszDeltas == ',')
|
|
cCommas++;
|
|
if (cCommas == 3)
|
|
break;
|
|
}
|
|
|
|
ewconst.dx = ewconst.dy = ewconst.wStyle = 0;
|
|
if (*pszDeltas != '\0') {
|
|
ASSERT(cCommas == 3);
|
|
|
|
// remove comma before dx
|
|
|
|
*pszDeltas++ = '\0';
|
|
pszDeltas = FirstNonSpace(pszDeltas, fDBCSSystem);
|
|
ewconst.dx = atoi(pszDeltas);
|
|
|
|
// skip up to comma before dy
|
|
|
|
while (*pszDeltas != '\0' && *pszDeltas++ != ',')
|
|
;
|
|
|
|
if (*pszDeltas != '\0') {
|
|
pszDeltas = FirstNonSpace(pszDeltas, fDBCSSystem);
|
|
ewconst.dy = atoi(pszDeltas);
|
|
}
|
|
}
|
|
else { // no dx and dy
|
|
if (cCommas < 2) {
|
|
|
|
// REVIEW: Print syntax error?
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// save the EW
|
|
|
|
if (fOutput) {
|
|
MOBJ mobjTemp;
|
|
char szBuf[sizeof(MOBJ)];
|
|
RC_TYPE rc;
|
|
|
|
int cbString = strlen(pszEw) + 1;
|
|
int cbEWCmd = sizeof(EWCONST) + cbString;
|
|
|
|
mobjTemp.bType = (BYTE) FCTYPE_WINDOW;
|
|
#ifdef MAGIC
|
|
mobjTemp.bMagic = bMagicMOBJ;
|
|
#endif
|
|
mobjTemp.lcbSize = cbEWCmd; // exclude object size
|
|
int cbCOBJ = CbPackMOBJ(&mobjTemp, szBuf);
|
|
rc = RcOutputCommand(bType, szBuf, cbCOBJ, TRUE);
|
|
|
|
// REVIEW: so how about reporting the error conditions? 05-Sep-1993 [ralphw]
|
|
|
|
if (rc == RC_Success) {
|
|
pbfCommand->Add(&ewconst, sizeof(EWCONST));
|
|
return pbfCommand->Add(pszEw, cbString);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
/***************************************************************************
|
|
*
|
|
- Name: VerifyCbmFiles
|
|
-
|
|
* Purpose:
|
|
* This function verifies that the CBM files are in such a state
|
|
* that they may be successfully abandoned.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
* nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
* This function will assert if anything goes wrong.
|
|
*
|
|
***************************************************************************/
|
|
|
|
void VerifyCbmFiles(void)
|
|
{
|
|
int iBmp;
|
|
LBM* qlbm;
|
|
|
|
if (pdrgBitmaps && pdrgBitmaps->Count() > 0) {
|
|
for (iBmp = 0, qlbm = (LBM*) pdrgBitmaps->GetBasePtr();
|
|
iBmp < pdrgBitmaps->Count();
|
|
iBmp++, qlbm++) {
|
|
|
|
// Skip spots for visual bitmaps
|
|
|
|
if (qlbm->fVisual)
|
|
continue;
|
|
|
|
if (qlbm->fmSource == NULL)
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* void VInsOnlineBitmap()
|
|
*
|
|
* Description:
|
|
*
|
|
* Returns;
|
|
*
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
void STDCALL VInsOnlineBitmap(RTF_BITMAP * qBitmap, ART art)
|
|
{
|
|
MOBJ mobjTemp;
|
|
WORD cbMobj;
|
|
char rgchBuf[sizeof(MOBJ)];
|
|
OBM obm;
|
|
DWORD cBitmap;
|
|
|
|
if (!pdrgBitmaps)
|
|
pdrgBitmaps = new CDrg(sizeof(LBM), 5, 5);
|
|
cBitmap = pdrgBitmaps->Count();
|
|
((LBM*) pdrgBitmaps->GetPtr(cBitmap))->fVisual = TRUE;
|
|
|
|
char szBmpName[20];
|
|
strcpy(szBmpName, "|bm");
|
|
_itoa(cBitmap, szBmpName + 3, 10);
|
|
|
|
// REVIEW
|
|
|
|
HF hf = HfCreateFileHfs(hfsOut, szBmpName, FS_READ_WRITE);
|
|
|
|
// convert the bitmap to internal format
|
|
|
|
if (RcWritePbitmap(qBitmap, art, hf) != RC_Success) {
|
|
RcAbandonHf(hf);
|
|
return;
|
|
}
|
|
|
|
RcCloseHf(hf);
|
|
|
|
if (qBitmap->fSingle)
|
|
pfCur.boxtype = BOXLINENORMAL;
|
|
else if (qBitmap->fThick)
|
|
pfCur.boxtype = BOXLINETHICK;
|
|
else if (qBitmap->fDouble)
|
|
pfCur.boxtype = BOXLINEDOUBLE;
|
|
else if (qBitmap->fDotted)
|
|
pfCur.boxtype = BOXLINEDOTTED;
|
|
else if (qBitmap->fShadow)
|
|
pfCur.boxtype = BOXLINESHADOW;
|
|
|
|
mobjTemp.bType = (BYTE) FCTYPE_BITMAP_COUNT;
|
|
mobjTemp.wObjInfo = 1;
|
|
#ifdef MAGIC
|
|
mobjTemp.bMagic = bMagicMOBJ;
|
|
#endif
|
|
mobjTemp.lcbSize = sizeof(OBM); // exclude object size
|
|
cbMobj = CbPackMOBJ(&mobjTemp, rgchBuf);
|
|
RcOutputCommand(CMD_INLINE_OBJ, rgchBuf, cbMobj, TRUE);
|
|
adrs.wObjrg++;
|
|
|
|
obm.fInline = FALSE;
|
|
obm.cBitmap = (INT) cBitmap;
|
|
pbfCommand->Add(&obm, sizeof(OBM));
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name FWritePbitmap
|
|
-
|
|
* Purpose
|
|
* This routine writes out the given graphic, as parsed from
|
|
* RTF, into the given filesystem file.
|
|
*
|
|
* Arguments
|
|
* pbitmap: A pointer to the extended bitmap structure as
|
|
* returned by the RTF parser.
|
|
* art: artWbitmap for windows bitmap, artWmetafile for
|
|
* a metafile.
|
|
* hf: Handle to filesystem file to save bitmap.
|
|
*
|
|
* Returns
|
|
* TRUE if successful.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
static RC_TYPE STDCALL RcWritePbitmap(RTF_BITMAP * pbitmap, ART art, HF hf)
|
|
{
|
|
CMem bmh(sizeof(BMH) + pbitmap->lcbBits);
|
|
PBMH pbmh = (PBMH) bmh.pb;
|
|
|
|
switch (art) {
|
|
case artWbitmap:
|
|
pbmh->bmFormat = bmWbitmap;
|
|
pbmh->fCompressed = BMH_COMPRESS_NONE;
|
|
pbmh->cbSizeBits = pbitmap->lcbBits;
|
|
pbmh->cbOffsetBits = sizeof( BMH );
|
|
pbmh->cbSizeExtra = 0L;
|
|
pbmh->cbOffsetExtra = 0L;
|
|
|
|
pbmh->w.dib.biSize = CB_COREINFO;
|
|
pbmh->w.dib.biWidth = pbitmap->bmWidth;
|
|
pbmh->w.dib.biHeight = pbitmap->bmHeight;
|
|
pbmh->w.dib.biPlanes = pbitmap->bmPlanes;
|
|
pbmh->w.dib.biBitCount = pbitmap->bmBitsPixel;
|
|
pbmh->w.dib.biCompression = 0L;
|
|
pbmh->w.dib.biSizeImage = 0L;
|
|
pbmh->w.dib.biClrUsed = 0L;
|
|
pbmh->w.dib.biClrImportant = 0L;
|
|
|
|
if (pbitmap->ptGoal.x < 0 || pbitmap->ptGoal.y < 0) {
|
|
pbmh->w.dib.biXPelsPerMeter = CX_DEFAULT_ASPECT;
|
|
pbmh->w.dib.biYPelsPerMeter = CY_DEFAULT_ASPECT;
|
|
}
|
|
else {
|
|
pbmh->w.dib.biXPelsPerMeter =
|
|
(144000L * pbitmap->bmWidth)
|
|
/ (pbitmap->ptGoal.x * pbitmap->ptScale.x);
|
|
pbmh->w.dib.biYPelsPerMeter =
|
|
(144000L * pbitmap->bmHeight)
|
|
/ (pbitmap->ptGoal.y * pbitmap->ptScale.y);
|
|
}
|
|
break;
|
|
|
|
case artWmetafile:
|
|
pbmh->bmFormat = bmWmetafile;
|
|
pbmh->fCompressed = BMH_COMPRESS_NONE;
|
|
|
|
pbmh->cbSizeBits = pbitmap->lcbBits;
|
|
pbmh->cbOffsetBits = (PBYTE)(&pbmh->w.mf.hMF) - (PBYTE)(pbmh);
|
|
pbmh->cbSizeExtra = 0;
|
|
pbmh->cbOffsetExtra = 0;
|
|
|
|
pbmh->w.mf.mm = pbitmap->bmType;
|
|
pbmh->w.mf.xExt = MulDiv(pbitmap->bmWidth, pbitmap->ptScale.x,
|
|
100);
|
|
pbmh->w.mf.yExt = MulDiv(pbitmap->bmHeight, pbitmap->ptScale.y,
|
|
100);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
memmove(QFromQCb(pbmh, pbmh->cbOffsetBits), pbitmap->bmBits,
|
|
pbitmap->lcbBits);
|
|
|
|
return RcWriteRgrbmh(1, (PBMH *) &pbmh, hf, NULL);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CountObjects
|
|
|
|
PURPOSE: If its a SHED or MRBC bitmap, fill in the number of of
|
|
objects
|
|
|
|
PARAMETERS:
|
|
qlbm
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
09-Mar-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
#include "fformat.h"
|
|
|
|
void STDCALL CountObjects(LBM* qlbm)
|
|
{
|
|
if (qlbm->fmTmp)
|
|
return;
|
|
|
|
// Check standard extensions for non-shed, non-mrbc bitmaps
|
|
|
|
CStr szFileName(qlbm->fmSource);
|
|
CharLower(szFileName);
|
|
if ( strstr(szFileName, ".bmp") ||
|
|
strstr(szFileName, ".pcx") ||
|
|
strstr(szFileName, ".eps") ||
|
|
strstr(szFileName, ".tif") ||
|
|
strstr(szFileName, ".dib"))
|
|
return;
|
|
|
|
// At this point, we're not sure what it is -- so find out
|
|
|
|
/*
|
|
* If we have file errors, just return without reporting the error.
|
|
* We'll report this error when we try to load the entire bitmap, so we
|
|
* just assume there are no objects and quietly return.
|
|
*/
|
|
|
|
CRead crFile(qlbm->fmSource);
|
|
if (crFile.hf == HFILE_ERROR)
|
|
return;
|
|
|
|
BMPH bmph;
|
|
|
|
if (crFile.read(&bmph, sizeof(BMPH)) != sizeof(BMPH))
|
|
return;
|
|
|
|
if (bmph.bVersion == bBmp)
|
|
return; // it's just a plain old bitmap
|
|
|
|
if (*((WORD *) &bmph.bVersion) == BMP_VERSION3 ||
|
|
*((WORD *) &bmph.bVersion) == BMP_VERSION2) {
|
|
int ibmh, cbmh = 0;
|
|
HBMH hbmh = HbmhReadHelp30Fid(&crFile, &cbmh);
|
|
if (hbmh == hbmhOOM || hbmh == hbmhInvalid)
|
|
return;
|
|
|
|
CMem memPBmh(cbmh * sizeof(PBMH));
|
|
CMem memHBmh(cbmh * sizeof(HBMH));
|
|
|
|
PBMH* prbmh = (PBMH *) memPBmh.pb;
|
|
HBMH* phbmh = (HBMH *) memHBmh.pb;
|
|
|
|
phbmh[0] = hbmh;
|
|
prbmh[0] = (PBMH) hbmh;
|
|
|
|
// Read in the rest of the bitmaps
|
|
|
|
WORD wObjrgT;
|
|
|
|
// REVIEW: Horribly inefficient -- we read all the bitmap data
|
|
// just to get the hotspot information.
|
|
|
|
CStr csz;
|
|
|
|
SzPartsFm(qlbm->fmSource, csz.psz, PARTBASE);
|
|
if (prbmh[0]->cbSizeExtra == 0 || !FEnumHotspotsLphsh(
|
|
(HSH*) ((PBYTE) prbmh[0] + prbmh[0]->cbOffsetExtra),
|
|
prbmh[0]->cbSizeExtra,
|
|
(PFNLPHS) CallbackLphs, (HANDLE) csz.psz)) {
|
|
FreeHbmh((PBMH) phbmh[0]);
|
|
return;
|
|
}
|
|
FreeHbmh((PBMH) phbmh[0]);
|
|
#ifdef _DEBUG
|
|
phbmh[0] = NULL;
|
|
#endif
|
|
|
|
for (ibmh = 1; ibmh < cbmh; ++ibmh) {
|
|
hbmh = HbmhReadHelp30Fid(&crFile, &ibmh);
|
|
if (hbmh == hbmhOOM || hbmh == hbmhInvalid) {
|
|
cbmh = ibmh; // number we have to free
|
|
break;
|
|
}
|
|
phbmh[ibmh] = hbmh;
|
|
prbmh[ibmh] = (PBMH) hbmh;
|
|
if (prbmh[ibmh]->cbSizeExtra != 0) {
|
|
if (!FEnumHotspotsLphsh(
|
|
(HSH*) ((PBYTE) prbmh[ibmh] + prbmh[ibmh]->cbOffsetExtra),
|
|
prbmh[ibmh]->cbSizeExtra,
|
|
(PFNLPHS) CallbackLphs, (HANDLE) csz.psz)) {
|
|
return;
|
|
}
|
|
memmove(&wObjrgT, (PBYTE) prbmh[ibmh] +
|
|
prbmh[ibmh]->cbOffsetExtra +
|
|
(int) &((HSH*) 0)->wcHotspots,
|
|
sizeof(WORD));
|
|
qlbm->wObjrg = MAX(qlbm->wObjrg, wObjrgT);
|
|
}
|
|
FreeHbmh((PBMH) phbmh[ibmh]);
|
|
#ifdef _DEBUG
|
|
phbmh[ibmh] = NULL; // make sure we don't free this again without an assertion
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
static void STDCALL CallbackLphs(HS* lphs, HANDLE hData)
|
|
{
|
|
VerifyShedBinding(lphs->bBindType, lphs->szBinding, (PSTR) hData);
|
|
}
|
|
|