460 lines
10 KiB
C++
460 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include "fcpriv.h"
|
|
#include "btpriv.h"
|
|
#include "fspriv.h"
|
|
#include "forage.h"
|
|
|
|
static int cbRead; // Number of bytes already read from qBuffer.
|
|
static int cbSystemFile; // Total number of bytes in |SYSTEM file buffer.
|
|
static PBYTE pSysBufRead; /* Points to point in |SYSTEM file buffer just after stuff
|
|
we've already read. */
|
|
|
|
static BOOL STDCALL FCheckSystem(QHHDR qhhdr, UINT* pwErr);
|
|
static BOOL STDCALL FReadBufferQch(LPBYTE, int);
|
|
static BOOL STDCALL FSkipReadBufferQch(WORD cbToRead);
|
|
|
|
#define PtrFromGh(x) (x)
|
|
#define PszFromGh(x) (x)
|
|
QRGWSMAG qrgwsmag;
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FReadBufferQch
|
|
-
|
|
* Purpose: To read from the System buffer and advance the count of what's
|
|
* been read. If qchToRead == NULL, then we just seek forward.
|
|
*
|
|
* Arguments: LPSTR qchToRead - Buffer to read System buffer into.
|
|
* LONG cbToRead - Number of bytes to read.
|
|
*
|
|
* Returns: BOOL - TRUE if read successful.
|
|
*
|
|
* Globals Used: pSysBufRead - The static pointer to where we are in the
|
|
* |SYSTEM buffer.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes: Trivial function, but making it a function makes things easier
|
|
* elsewhere.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static BOOL STDCALL FReadBufferQch(LPBYTE qchToRead, int cbToRead)
|
|
{
|
|
if ((cbRead + cbToRead) > cbSystemFile)
|
|
return FALSE;
|
|
if (qchToRead != NULL)
|
|
MoveMemory(qchToRead, pSysBufRead, cbToRead);
|
|
pSysBufRead += cbToRead;
|
|
cbRead += cbToRead;
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: FSkipReadBufferQch
|
|
|
|
PURPOSE: Skip over the specified amount of data
|
|
|
|
PARAMETERS:
|
|
cbToRead
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
24-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static BOOL STDCALL FSkipReadBufferQch(WORD cbToRead)
|
|
{
|
|
if ((cbRead + cbToRead) > cbSystemFile)
|
|
return FALSE;
|
|
pSysBufRead += cbToRead;
|
|
cbRead += cbToRead;
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FReadSystemFile
|
|
-
|
|
* Purpose:
|
|
* Reads in the tagged data from the |SYSTEM file
|
|
*
|
|
* Arguments:
|
|
* hfs - handle to file system to read
|
|
* pdb - near pointer to DB struct to fill
|
|
* pwErr - pointer to place error word
|
|
*
|
|
* Returns: True if valid version number, system file
|
|
* pdb is changed
|
|
*
|
|
* Globals Used: pSysBufRead, cbRead, cbSystemFile
|
|
*
|
|
* History:
|
|
* 24-Feb-1993 [ralphw] Added fTitleOnly for when we build a master
|
|
* keyword list.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define QHFSYSTEM "|SYSTEM" // system file
|
|
#define RcGetFSError() (rcFSError)
|
|
|
|
__inline int LcbSizeHf(HF hf) {
|
|
ASSERT(hf != NULL);
|
|
return ((QRWFO) hf)->lcbFile;
|
|
};
|
|
|
|
|
|
extern QRGWSMAG qrgwsmag;
|
|
|
|
BOOL STDCALL FReadSystemFile (
|
|
HFS hfs,
|
|
PDB pdb,
|
|
UINT* pwErr,
|
|
BOOL fTitleOnly
|
|
) {
|
|
HF hf;
|
|
TAG tagRead;
|
|
WORD cbData;
|
|
LPBYTE qBuffer;
|
|
LPSTR lpszTempBuf;
|
|
BOOL fIconTag = FALSE; // set to TRUE if the icon is present in file.
|
|
UINT iWsmag = 0; // count of smags seen
|
|
|
|
*pwErr = wERRS_BADFILE; // REVIEW - is this a reasonable default????
|
|
|
|
// Initialize fields of DE to default values:
|
|
|
|
PDB_ADDRCONTENTS(pdb) = addrNil;
|
|
|
|
// Open the |SYSTEM subsystem.
|
|
|
|
if ((hf = HfOpenHfs((QFSHR) hfs, QHFSYSTEM, FS_OPEN_READ_ONLY)) == NULL) {
|
|
if (RcGetFSError() == RC_OutOfMemory)
|
|
*pwErr = wERRS_OOM;
|
|
else
|
|
*pwErr = wERRS_BADFILE; // this is good enough
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the size of the |SYSTEM file, and read it into a buffer.
|
|
|
|
cbSystemFile = LcbSizeHf(hf);
|
|
CMem mem(cbSystemFile);
|
|
qBuffer = mem.pb;
|
|
|
|
if (!qBuffer) {
|
|
*pwErr = RC_OutOfMemory;
|
|
goto error_quit;
|
|
}
|
|
|
|
if (!LcbReadHf(hf, qBuffer, cbSystemFile)) {
|
|
if (RcGetFSError() == RC_OutOfMemory)
|
|
*pwErr = RC_OutOfMemory;
|
|
else
|
|
*pwErr = RC_BadVersion;
|
|
goto error_close;
|
|
}
|
|
pSysBufRead = qBuffer;
|
|
cbRead = 0;
|
|
|
|
Ensure(RcCloseHf(hf), RC_Success);
|
|
|
|
if (!FCheckSystem(&pdb->hhdr, pwErr))
|
|
goto error_return;
|
|
|
|
// If this is a 3.0 file, just read in the title like we used to.
|
|
|
|
if (PDB_HHDR(pdb).wVersionNo == wVersion3_0) {
|
|
if (!FReadBufferQch((unsigned char *) PDB_RGCHTITLE(pdb), (cbSystemFile - cbRead))) {
|
|
*pwErr = RC_BadVersion;
|
|
goto error_return;
|
|
}
|
|
goto ok_return;
|
|
}
|
|
|
|
// Loop through all tags, reading the data and putting it someplace.
|
|
|
|
kwlcid.langid = 0;
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// TAG's are 16 bit values. This code is endian dependent.
|
|
//
|
|
*((int *)&tagRead) = 0;
|
|
if (!FReadBufferQch((LPBYTE) &tagRead, sizeof(WORD)))
|
|
break; // Out of tags.
|
|
|
|
ASSERT ((tagRead > tagFirst) && (tagRead < tagLast));
|
|
|
|
if (!FReadBufferQch((LPBYTE) &cbData, sizeof(WORD)))
|
|
goto error_return;
|
|
|
|
if (fTitleOnly)
|
|
{
|
|
if (tagRead == tagTitle)
|
|
{
|
|
lpszTempBuf = PDB_RGCHTITLE(pdb);
|
|
|
|
if (!FReadBufferQch((unsigned char *) lpszTempBuf, cbData))
|
|
goto error_return;
|
|
else
|
|
goto ok_return; // we don't care about any other tags
|
|
}
|
|
else
|
|
{
|
|
if (!FSkipReadBufferQch(cbData))
|
|
goto error_return;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// The valye of tagRead decides where we will read the data into.
|
|
|
|
switch (tagRead)
|
|
{
|
|
case tagTitle:
|
|
lpszTempBuf = PDB_RGCHTITLE(pdb);
|
|
break;
|
|
|
|
case tagCopyright:
|
|
lpszTempBuf = PDB_RGCHCOPYRIGHT(pdb);
|
|
break;
|
|
|
|
case tagContents:
|
|
lpszTempBuf = (LPSTR) &PDB_ADDRCONTENTS(pdb);
|
|
break;
|
|
|
|
case tagCitation:
|
|
|
|
/*
|
|
* Citation tag: additional text to be appended to the end of
|
|
* copy-to-clipboard. Just stick in some global memory referenced
|
|
* by the DB, where it can be picked up when needed by the copy
|
|
* code.
|
|
*/
|
|
|
|
if (PDB_HCITATION(pdb))
|
|
lcFree(PDB_HCITATION(pdb));
|
|
|
|
PDB_HCITATION(pdb) = (LPSTR) lcMalloc(cbData);
|
|
|
|
if (!FReadBufferQch((unsigned char *) PtrFromGh(PDB_HCITATION(pdb)), cbData))
|
|
goto error_return;
|
|
|
|
ASSERT ((WORD)lstrlen((const char *) pSysBufRead) < cbData);
|
|
|
|
lpszTempBuf = NULL;
|
|
cbData = 0;
|
|
break;
|
|
|
|
case tagConfig:
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
case tagIcon:
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
case tagWindow:
|
|
|
|
// window tag. We collect all the wsmag structures into a single
|
|
// block of memory, and hang that sucker off the de.
|
|
|
|
if (!PDB_HRGWSMAG(pdb)) {
|
|
|
|
/*
|
|
* Block has not yet been allocated. We always allocate
|
|
* the maximum size block, just because managing it as
|
|
* variable size is more of a pain than it's worth. When we
|
|
* go to multiple secondary windows and the number increases,
|
|
* this will no longer be true.
|
|
*/
|
|
|
|
ASSERT (iWsmag == 0);
|
|
|
|
// REVIEW: could probably just used LMEM_FIXED
|
|
|
|
PDB_HRGWSMAG(pdb) = (HWSMAG) lcMalloc(sizeof(RGWSMAG));
|
|
if (!PDB_HRGWSMAG(pdb)) {
|
|
*pwErr = wERRS_OOM;
|
|
goto error_return;
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Increase the size to allow for the new window array
|
|
|
|
PDB_HRGWSMAG(pdb) = (HWSMAG) lcReAlloc(PDB_HRGWSMAG(pdb),
|
|
sizeof(RGWSMAG) + sizeof(WSMAG) *
|
|
(((QRGWSMAG) PtrFromGh(PDB_HRGWSMAG(pdb)))->cWsmag + 1));
|
|
if (!PDB_HRGWSMAG(pdb)) {
|
|
*pwErr = wERRS_OOM;
|
|
goto error_return;
|
|
}
|
|
}
|
|
|
|
qrgwsmag = (QRGWSMAG) PtrFromGh(PDB_HRGWSMAG(pdb));
|
|
|
|
// Increment the count of structures in the block, point at the
|
|
// appropriate new slot, and copy in the new structure.
|
|
|
|
qrgwsmag->rgwsmag[iWsmag++] = *(QWSMAG) pSysBufRead;
|
|
qrgwsmag->cWsmag = iWsmag;
|
|
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
// The following are new to 4.0
|
|
|
|
case tagLCID: // Locale Identifier and CompareStringA flags
|
|
lpszTempBuf = (LPSTR) &kwlcid;
|
|
break;
|
|
|
|
case tagCHARSET: // default charset to use
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
case tagCNT:
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
case tagPopupColor:
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
case tagDefFont:
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
case tagIndexSep:
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unimplemented tag. Ignore it.
|
|
|
|
ASSERT(FALSE);
|
|
|
|
lpszTempBuf = NULL;
|
|
break;
|
|
}
|
|
|
|
if (!FReadBufferQch((unsigned char *)lpszTempBuf, cbData))
|
|
goto error_return;
|
|
}
|
|
|
|
ok_return:
|
|
|
|
if (kwlcid.langid)
|
|
lcid = MAKELCID(kwlcid.langid, SORT_DEFAULT);
|
|
return TRUE;
|
|
|
|
error_close:
|
|
Ensure(RcCloseHf(hf), RC_Success);
|
|
error_return:
|
|
error_quit:
|
|
//
|
|
// BUGBUG want an error report here?
|
|
//if (*pwErr == RC_Error || *pwErr == RC_BadVersion) {
|
|
// char szName[_MAX_PATH];
|
|
// lstrcpy(szName, PszFromGh(PDB_FM(pdb)));
|
|
// ErrorVarArgs(*pwErr, wERRA_RETURN, szName);
|
|
//}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************
|
|
*
|
|
- FCheckSystem
|
|
-
|
|
* purpose
|
|
* Verifies that the file system can be displayed by this version
|
|
* of the software.
|
|
*
|
|
* arguments
|
|
* QHHDR qhhdr - far pointer to help header structure
|
|
*
|
|
* return value
|
|
* TRUE iff valid
|
|
* return system help header in qhhdr
|
|
*
|
|
* globals used
|
|
* pSysBufRead - The static pointer to where we are in the |SYSTEM buffer
|
|
*
|
|
**************/
|
|
|
|
static BOOL STDCALL FCheckSystem(QHHDR qhhdr, UINT* pwErr)
|
|
{
|
|
|
|
/* (kevynct)
|
|
* We read Help 3.0, 3.1 (3.5) or 4.0 files. But certain in-between
|
|
* versions of Help 3.5 files are no longer supported. The format number
|
|
* in the header now indicates a sub-version of a supported version, and
|
|
* so is not checked here.
|
|
*/
|
|
|
|
// Read in the first field of the HHDR, the Magic number.
|
|
|
|
if ((!FReadBufferQch((LPBYTE) &qhhdr->wMagic, sizeof(WORD)))
|
|
|| (qhhdr->wMagic != MagicWord)) {
|
|
*pwErr = RC_BadVersion;
|
|
return FALSE;
|
|
}
|
|
|
|
// Read in the rest of the fields, except for those that are new.
|
|
|
|
if ((! FReadBufferQch((LPBYTE) &qhhdr->wVersionNo, sizeof(WORD)))
|
|
|| (! FReadBufferQch((LPBYTE) &qhhdr->wVersionFmt, sizeof(WORD)))
|
|
|| (! FReadBufferQch((LPBYTE) &qhhdr->lDateCreated, sizeof(LONG)))
|
|
|| (! FReadBufferQch((LPBYTE) &qhhdr->wFlags, sizeof(WORD)))) {
|
|
*pwErr = RC_BadVersion;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* WARNING: Version dependency: Fix for Help 3.5 bug 488. The Help 3.0
|
|
* and 3.1 compilers do not initialize the wFlags bits. Only the fDebug
|
|
* bit is used.
|
|
*/
|
|
|
|
if (qhhdr->wVersionNo == wVersion3_0) {
|
|
qhhdr->wFlags &= fDEBUG;
|
|
}
|
|
|
|
if ((qhhdr->wMagic != MagicWord)
|
|
|| ((qhhdr->wVersionNo < wVersion3_5)
|
|
&& qhhdr->wVersionNo != wVersion3_0)
|
|
) {
|
|
*pwErr = RC_BadVersion;
|
|
return FALSE;
|
|
}
|
|
|
|
if (qhhdr->wVersionNo > VersionNo)
|
|
{
|
|
*pwErr = RC_BadVersion;
|
|
goto error_return;
|
|
}
|
|
|
|
#if 0
|
|
if ((qhhdr->wFlags & fDEBUG) != fVerDebug) {
|
|
*pwErr = wERRS_DEBUGMISMATCH;
|
|
goto error_return;
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
error_return:
|
|
//
|
|
// BUGBUG error reporting.
|
|
// PostErrorMessage(*pwErr);
|
|
return FALSE;
|
|
}
|