Windows NT 4.0 source code leak
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

/****************************************************************************
* *
* 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);
}