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.
 
 
 
 
 
 

1166 lines
27 KiB

/*****************************************************************************
* *
* BOOKMARK.C *
* *
* Copyright (C) Microsoft Corporation 1989, 1990, 1991. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* *
* Bookmark module, platform independent part. *
*
*****************************************************************************/
#include "help.h"
#pragma hdrstop
#include "inc\bookmark.h"
/*****************************************************************************
* *
* Defines *
* *
*****************************************************************************/
/*
Macro to return size in bytes of the disk image of the header
of a bookmark file of the given version.
*/
#define CB_BMKHDR(wVer) ((wVer) == wVersion3_0 ? \
sizeof(BMKHDR3_0) : sizeof(BMKHDR3_5))
/*
Buffer size for bookmark file name: contains space for base name
of help file + space for timestamp in hex.
*/
#define MAX_BMK_FILENAME (_MAX_FNAME + 2 * sizeof(LONG))
/*****************************************************************************
* *
* Typedefs *
* *
*****************************************************************************/
/*
Header at the beginning of a 3.0 bookmark file.
I'm not sure whether wBMOffset is always 0 on disk.
*/
typedef struct {
WORD cBookmarks; // number of bookmarks in the file
WORD cbFile; // size of file in bytes including header
WORD cbOffset; // offset to current bookmark;
/* only has meaning at runtime */
} BMKHDR3_0, *QBMKHDR3_0;
/*
Header at the beginning of a 3.5 bookmark file.
Review: Do we need timestamp here if it's in bookmark filename too?
*/
typedef struct {
WORD wVersion; // bookmark format version number
LONG lTimeStamp; // timestamp from help file
WORD cBookmarks; // number of bookmarks in the file
WORD cbFile; // size of file in bytes including header
} BMKHDR3_5, *QBMKHDR3_5;
typedef union
{
BMKHDR3_0 bmkhdr3_0;
BMKHDR3_5 bmkhdr3_5;
} BMKHDR_DISK, *QBMKHDR_DISK;
/*****************************************************************************
* *
* Static Variables *
* *
*****************************************************************************/
/*
This HFS specifies the unique bookmark file system. It is opened
only when needed because of reentrancy problems with multiple instances
in the FS code.
*/
HFS hfsBM;
/*
This is a group of flags containing error information.
*/
static int iBMKError; // iBMKNoError;
/*****************************************************************************
* *
* Prototypes *
* *
*****************************************************************************/
INLINE static int STDCALL RetBkMkInfo(QBMKHDR_RAM, PBI);
INLINE static int STDCALL CbBmk(QBMKHDR_RAM qbh_r, WORD wOffset);
static void STDCALL SetBMKFSError(void);
INLINE static HF HfOpenBookmarkFile(QDE qde);
static void BmkFilename(QDE qde, PSTR pszFilename);
static BOOL STDCALL ChkBMFS(void);
INLINE static QBMKHDR_RAM STDCALL QramhdrFromDisk(QBMKHDR_RAM, QBMKHDR_DISK, WORD);
INLINE static QBMKHDR_DISK STDCALL QdiskhdrFromRam(QBMKHDR_DISK, QBMKHDR_RAM, LONG);
/***************************************************************************\
*
- Function: RcLoadBookmark( qde )
-
* Purpose: Guarantee that bookmarks for the current help file, if
* any exist, are loaded.
*
* ASSUMES
* args IN: QDE_BMK(qde) - if NULL, load
* QDE_HHDR(qde).wVersionNo - what helpfile version?
* QDE_HHDR(qde).lDateCreated - creation date of helpfile
* state IN:
*
* PROMISES
* returns: rcSuccess - successfully loaded, or no bookmarks exist
* rcFailure - OOM or FS error: trouble
* rcBadVersion - a version mismatch was encountered,
* bookmarks converted automatically
* args OUT: QDE_BMK(qde) - contains bmk info on success, else NULL
* globals OUT: iBMKError - set some flags to reflect error conditions
* state OUT:
*
* Side Effects:
*
* Notes:
*
* Bugs:
*
* +++
*
* Method: Check version and look for bookmark file of the appropriate
* name. Check timestamp.
*
* Notes:
*
\***************************************************************************/
RC STDCALL RcLoadBookmark(QDE qde)
{
BMK bmk = NULL;
BMKHDR_DISK bh_d;
QBMKHDR_RAM qbh_r;
QHHDR qhhdr = &QDE_HHDR( qde );
WORD wVersion = qhhdr->wVersionNo;
BOOL fVersion3_0 = ( wVersion == wVersion3_0 );
LONG lcbHeader;
LONG lcbFile;
RC rc = rcSuccess;
RC rcT;
HF hf;
ASSERT( qde != NULL );
// REVIEW: this needs to be checked each time we do [what]???
if (iBMKError & iBMKFSError)
return rcFailure;
if (QDE_BMK(qde) == NULL) { // bookmarks aren't loaded
hf = HfOpenBookmarkFile( qde );
if (hf == NULL) {
// Either there is no bookmark file or there is an error.
// If error, iBMKError has been set by HfOpenBookmarkFile().
// (Do nothing.)
}
else
{
lcbFile = LcbSizeHf( hf );
if ( lcbFile == 0L )
{
iBMKError |= iBMKFSReadWrite;
(void)RcCloseHf( hf );
return rcFailure;
}
lcbHeader = fVersion3_0 ? sizeof( BMKHDR3_0 ) : sizeof( BMKHDR3_5 );
bmk = GhAlloc(GPTR, lcbFile - lcbHeader + sizeof( BMKHDR_RAM ) );
if ( bmk == NULL )
{
iBMKError |= iBMKOom;
(void)RcCloseHf( hf );
return rcFailure;
}
qbh_r = PtrFromGh(bmk);
/* qbh_r + 1 points just past the header. */
if ( LcbReadHf( hf, &bh_d, lcbHeader ) != lcbHeader
||
( LcbReadHf( hf, qbh_r + 1, lcbFile - lcbHeader )
!=
lcbFile - lcbHeader ) )
{
iBMKError |= iBMKFSReadWrite;
(void)RcCloseHf( hf );
FreeGh(bmk);
QDE_BMK( qde ) = NULL;
return rcFailure;
}
(void)QramhdrFromDisk( qbh_r, &bh_d, wVersion );
#if 0
/* Timestamp checking is done with bookmark file name, but */
/* this needs to be reviewed with HeikkiK. */
if ( !fVersion3_0
&&
bh_d.bmkhdr3_5.lTimeStamp != qhhdr->lDateCreated )
{
LSeekHf(hf, offsetof(BMKHDR3_5, lTimeStamp), wFSSeekSet);
LcbWriteHf(hf, &(qhhdr->lDateCreated), sizeof(LONG));
// and remember for return
rc = rcBadVersion;
}
#endif // 0
qbh_r->cbOffset = 0;
rcT = RcCloseHf( hf );
if ( rcT != rcSuccess ) rc = rcT;
QDE_BMK(qde) = bmk;
}
}
return rc;
}
/***************************************************************************\
*
- Function: GetBkMkNext( qde, pbi, wMode )
-
* Purpose: Return title and TLP of a specified bookmark.
* wMode is either BMSEQNEXT or index (0 based) of
* bookmark to retrieve.
*
* ASSUMES
* args IN: QDE_BMK( qde ) - bookmark data
* pbi->cbOffset - offset of last bookmark looked up
* wMode - BMSEQNEXT: get next bookmark
* >= 0: wMode'th bookmark (0 based)
* globals IN:
* state IN:
*
* PROMISES
* returns: -1 - error
* 0 - EOF : no more bookmarks
* >0 - size of this bookmark
*
* args OUT: qde->cbOffset - incremented past retrieved bookmark
* pbi - bookmark data copied here
*
* globals OUT:
* state OUT:
*
\***************************************************************************/
int STDCALL GetBkMkNext(QDE qde, PBI pbi, UINT wMode)
{
BOOL fSeqOn = TRUE;
UINT wT;
int iRetVal = 0;
WORD wOff;
QBMKHDR_RAM qbh_r;
if (QDE_BMK(qde)) {
qbh_r = PtrFromGh(QDE_BMK(qde));
if (!wMode) { // Give the first book mark // REVIEW: unnecessary
qbh_r->cbOffset = sizeof(BMKHDR_RAM);
}
else if (!(wMode & BKMKSEQNEXT)) {
if (qbh_r->cBookmarks < wMode) {
NotReached();
iRetVal = -1;
}
else {
wOff = sizeof(BMKHDR_RAM);
for (wT = 0; wT < wMode; wT++) {
wOff += CbBmk(qbh_r, wOff);
}
qbh_r->cbOffset = wOff; // bookmark size
fSeqOn = FALSE;
}
}
if (qbh_r->cbOffset < qbh_r->cbMem && iRetVal >= 0) {
iRetVal = RetBkMkInfo(qbh_r, pbi);
if (!fSeqOn) // if not sequential
qbh_r->cbOffset = sizeof(BMKHDR_RAM);
else
qbh_r->cbOffset += iRetVal;
}
}
return(iRetVal);
}
/*-----------------------------------------------------------------------------
* INT RetBkMkInfo( QBMKHDR_RAM, PBI )
*
* Description:
* This function returns the BM Info. from the BM List as pointed by
* the BM POINTER.( internally maintained)
*
* Arguments:
* 1. QBMKHDR_RAM - Pointer to bookmark data
* 2. PBI - pointer to BMINFO structure where BM info is returned.
*
* Returns;
* returns the size of current BM
* WARNING:
* This function doesn't check whether BM pointer is at EOF. (???)
*-----------------------------------------------------------------------------*/
INLINE static int STDCALL RetBkMkInfo(QBMKHDR_RAM qbh_r, PBI pbi)
{
QB qb = (QB)qbh_r;
qb += qbh_r->cbOffset;
MoveMemory(&(pbi->tlp), qb, sizeof(TLP));
/* 3.0 TLPs must be converted to VA format. */
if ( qbh_r->wVersion == wVersion3_0 )
{
OffsetToVA30( &(pbi->tlp.va), pbi->tlp.va.dword );
}
qb += sizeof( TLP );
SzNCopy( pbi->qTitle, qb, pbi->iSizeTitle );
pbi->qTitle[pbi->iSizeTitle-1] = '\0';
return( sizeof( TLP ) + lstrlen( qb ) + 1 );
}
/***************************************************************************\
*
- Function: CbBmk( qbh_r, cb )
-
* Purpose: Return size in bytes of bookmark starting at offset given
* in bookmark data structure given.
*
* ASSUMES
* args IN: qbh_r - pointer to bookmark header followed by data
* cb - offset in bytes of the bookmark data
* globals IN:
* state IN:
*
* PROMISES
* returns: size in bytes of the bookmark at (QB)qbh_r + cb
*
\***************************************************************************/
INLINE static int STDCALL CbBmk(QBMKHDR_RAM qbh_r, WORD cb)
{
ASSERT(cb + sizeof(TLP) < qbh_r->cbMem);
ASSERT(cb + sizeof(TLP) + lstrlen((QB) qbh_r + cb + sizeof(TLP)) + 1
<
qbh_r->cbMem);
return sizeof(TLP) + lstrlen((QB) qbh_r + cb + sizeof(TLP)) + 1;
}
/*-----------------------------------------------------------------------------
* TLP JumpToBkMk( HDE, iBkMk )
*
* Description:
* Return the TLP stored for the bookmark specified by given index.
*
* Arguments:
* 1. HDE - Pointer to the Display Environment(DE)
* 2. iBkMk- Bookmark number
*
* Returns:
* returns the TLP for the BM
*-----------------------------------------------------------------------------*/
TLP STDCALL JumpToBkMk(HDE hde, int iBkMk)
{
BMINFO BkMk;
char rgTitle[BMTITLESIZE + 1];
QDE qde;
BkMk.qTitle = rgTitle;
BkMk.iSizeTitle = BMTITLESIZE;
qde = QdeFromGh(hde);
if (GetBkMkNext(qde, &BkMk, (WORD) iBkMk) <= 0) {
BkMk.tlp.va.dword = vaNil; // error - verify from Rob
BkMk.tlp.lScroll = -1;
}
return (BkMk.tlp);
}
/***************************************************************************\
*
- Function: GetBkMkIdx( hde, qch )
-
* Purpose: Look up a bookmark by title, returning index.
*
* ASSUMES
* args IN: hde - current hde (REVIEW: should take a BMK)
* qch - title string
* globals IN:
* state IN:
*
* PROMISES
* returns: if found, index of bookmark (0-based)
* if not found, -1
* state OUT: REVIEW: may indirectly change cbOffset of BMK in DE
*
\***************************************************************************/
int STDCALL GetBkMkIdx(HDE hde, PCSTR qch)
{
BMINFO BkMk;
char rgTitle[BMTITLESIZE + 1];
WORD wMode=0;
int iT;
QDE qde;
qde = QdeFromGh(hde);
ASSERT(qde);
BkMk.qTitle = rgTitle;
BkMk.iSizeTitle = BMTITLESIZE;
for (iT = 0;; iT++) {
if (GetBkMkNext(qde, &BkMk, wMode) <= 0) {
iT = -1;
break;
}
if (!strcmp(BkMk.qTitle, qch))
break;
wMode = BKMKSEQNEXT;
}
return (iT);
}
/***************************************************************************\
*
- Function: DeleteBkMk( hde, qchTitle )
-
* Purpose: Delete the bookmark with the specified title, if one exists.
*
* ASSUMES
* args IN: hde: BMK - handle to bookmarks for current help file
* qchTitle - title of bookmark to be deleted
* globals IN:
* state IN:
*
* PROMISES
* returns: iBMKSuccess - bookmark successfully deleted
* iBMKFailure - bookmark didn't exist, OOM, or other error
* args OUT:
* globals OUT: iBMKError
* state OUT:
*
* Side Effects:
* Notes: Should return BOOL.
* Bugs:
* +++
* Method: Look up the bookmark by name. Copy it to a save buffer.
* Delete it and save the file. If there was any error,
* copy the deleted bookmark back into the in-memory
* bookmark data.
* Notes:
*
\***************************************************************************/
int STDCALL DeleteBkMk(HDE hde, LPCSTR qchTitle)
{
BMINFO bmi;
HF hf;
BMK bmk;
LPSTR qchBkMkTemp;
int iRetVal = iBMKSuccess;
int cbBmk;
WORD wMode=0;
WORD wCount, wOldSize;
QDE qde;
int cbHeader, cbRest;
LPSTR qchUndoSrc, qchUndoDest;
char rgchUndoBuf[128]; // REVIEW: what does this size mean???
WORD wUndoCount;
int iUndoBkMkSize;
QBMKHDR_RAM qbh_r;
BMKHDR_DISK bh_d;
WORD wVersion;
LONG lTimeStamp;
QHHDR qhhdr;
char nszFilename[MAX_BMK_FILENAME];
GH ghTitle;
if (!ChkBMFS())
return iBMKFailure;
ASSERT(hfsBM != NULL);
ASSERT(hde != NULL);
qde = QdeFromGh(hde);
if (QDE_BMK(qde)) {
// build a BMINFO struct for GetBkMkNext()
ghTitle = GhAlloc(GPTR, BMTITLESIZE + 1);
if (ghTitle == NULL) {
iBMKError |= iBMKOom;
return iBMKFailure;
}
bmi.qTitle = PtrFromGh(ghTitle);
bmi.iSizeTitle = BMTITLESIZE;
// Look for the bookmark we want to delete.
for (cbBmk = GetBkMkNext(qde, &bmi, 0);
cbBmk > 0 && strcmp(bmi.qTitle, qchTitle); // DO NOT USE lstrcmp!!!
cbBmk = GetBkMkNext(qde, &bmi, BKMKSEQNEXT)) {
// null statement
}
if (cbBmk <= 0) {
iBMKError |= iBMKDelErr;
iRetVal = iBMKFailure;
}
else {
qbh_r = PtrFromGh(QDE_BMK(qde));
ASSERT(qbh_r != NULL);
qchBkMkTemp = (LPSTR) qbh_r + qbh_r->cbOffset - cbBmk;
wCount = qbh_r->cbMem - qbh_r->cbOffset;
wUndoCount = wCount;
if (wUndoCount) {
qchUndoDest = qchBkMkTemp;
qchUndoSrc = (QB) qbh_r + qbh_r->cbOffset;
iUndoBkMkSize = cbBmk;
MoveMemory(rgchUndoBuf, qchBkMkTemp, (LONG) cbBmk);
MoveMemory(qchBkMkTemp, qchUndoSrc, (LONG) wCount);
}
wOldSize = qbh_r->cbMem;
qbh_r->cbMem -= cbBmk;
qbh_r->cbOffset = 0;
--qbh_r->cBookmarks;
// Get the name of the bookmark file so we can change its contents.
BmkFilename(qde, nszFilename);
if (qbh_r->cBookmarks) {
hf = HfOpenHfs(hfsBM, nszFilename, fFSOpenReadWrite);
if (hf == NULL) {
SetBMKFSError();
goto error_return;
}
qhhdr = &QDE_HHDR(qde);
lTimeStamp = qhhdr->lDateCreated;
wVersion = qhhdr->wVersionNo;
cbHeader = CB_BMKHDR(wVersion);
cbRest = qbh_r->cbMem - sizeof(BMKHDR_RAM);
(void) QdiskhdrFromRam(&bh_d, qbh_r, lTimeStamp);
// Note that qbh_r + 1 points just past header
if (LcbWriteHf(hf, &bh_d, cbHeader) != cbHeader
||
LcbWriteHf(hf, qbh_r + 1, cbRest) != cbRest) {
SetBMKFSError();
RcAbandonHf(hf);
goto error_return;
}
// resize the file
if (!FChSizeHf(hf, cbHeader + cbRest)) {
SetBMKFSError();
RcAbandonHf(hf);
goto error_return;
}
if (RcCloseHf(hf) != rcSuccess
||
RcFlushHfs(hfsBM, fFSCloseFile) != rcSuccess ) {
SetBMKFSError();
goto error_return;
}
bmk = GhResize(QDE_BMK(qde), 0, (DWORD) qbh_r -> cbMem);
if (bmk == NULL) {
iBMKError |= iBMKOom;
goto error_ret2;
}
else
QDE_BMK(qde) = bmk;
}
else { // we've just deleted the only bookmark for this helpfile
if (RcUnlinkFileHfs(hfsBM, nszFilename) != rcSuccess) {
SetBMKFSError();
goto error_return;
}
FreeGh(QDE_BMK(qde));
QDE_BMK(qde) = NULL;
}
}
FreeGh(ghTitle);
}
return(iRetVal);
error_return:
if (wUndoCount) {
MoveMemory(qchUndoSrc, qchUndoDest, (DWORD) wUndoCount);
MoveMemory(qchUndoDest, rgchUndoBuf, (DWORD) iUndoBkMkSize);
}
qbh_r->cbMem = wOldSize;
qbh_r->cBookmarks += 1;
error_ret2:
FreeGh(ghTitle);
return iBMKFailure;
}
/***************************************************************************\
*
- Function: InsertBkMk( hde, qchTitle )
-
* Purpose: Add a bookmark containing the current TLP and the
* specified title, if there isn't already one with this name.
*
* ASSUMES
* args IN: hde: BMK - handle to bookmarks for this file
* TLP - contains TLP of currently displayed topic
* HHDR - wVersionNo is version of current help file
* qchTitle - title of bookmark to be created
* globals IN:
* state IN:
*
* PROMISES
* returns: bmkSuccess -
* bmkFailure - if name duplicated
* args OUT:
* globals OUT:
* state OUT:
*
* Side Effects:
* Notes:
* Bugs: Should return a BOOL, not an INT (should be renamed, too!)
* +++
* Method:
* Notes:
*
\***************************************************************************/
int STDCALL InsertBkMk(HDE hde, LPCSTR qchTitle)
{
BMINFO BkMk;
char rgchTitle[BMTITLESIZE + 1];
HF hf;
BMK bmk;
WORD wMode = 0;
int iRetVal = iBMKSuccess;
int cchTitle;
LPSTR qchT;
WORD wSize, wSizeOld;
QDE qde;
TLP tlp;
QBMKHDR_RAM qbh_r;
BMKHDR_DISK bh_d;
char nszFilename[MAX_BMK_FILENAME];
QHHDR qhhdr;
LONG lTimeStamp;
WORD wVersion;
int cbHeader;
if (!ChkBMFS())
return(iBMKFailure);
ASSERT(hfsBM != NULL);
ASSERT(hde != NULL);
qde = QdeFromGh(hde);
BmkFilename(qde, nszFilename);
tlp = TLPGetCurrentQde(qde);
qhhdr = &QDE_HHDR(qde);
wVersion = qhhdr->wVersionNo;
// Convert back to 3.0 format before writing to bookmark file.
if (wVersion == wVersion3_0)
tlp.va.dword = VAToOffset30(&(tlp.va));
if (QDE_BMK(qde)) {
BkMk.qTitle = rgchTitle;
BkMk.iSizeTitle = BMTITLESIZE;
for (;;) {
if (GetBkMkNext(qde, &BkMk, wMode) <= 0)
break;
if (!strcmp(BkMk.qTitle, qchTitle)) { // DO NOT USE lstrcmp!!!
iBMKError |= iBMKDup;
iRetVal = iBMKFailure;
break;
}
wMode = BKMKSEQNEXT;
}
}
if (iRetVal == iBMKSuccess) {
cchTitle = lstrlen(qchTitle) + 1;
if (!QDE_BMK(qde)) {
wSizeOld = sizeof(BMKHDR_RAM);
wSize = wSizeOld + sizeof(TLP) + cchTitle;
QDE_BMK(qde) = GhAlloc(GPTR, (LONG) wSize);
if (!QDE_BMK(qde)) {
iBMKError |= iBMKOom;
return(iBMKFailure);
}
#ifdef _DEBUG
/*
This code relies on getting 0-filled memory from GhAlloc().
Since our debug layer doesn't allow this, we zero out some
fields in the DEBUG case.
*/
qbh_r = PtrFromGh(QDE_BMK(qde));
qbh_r->cbOffset = 0;
qbh_r->cbMem = 0;
qbh_r->cBookmarks = 0;
#endif // defined( DEBUG )
}
else
{
qbh_r = PtrFromGh(QDE_BMK(qde));
wSizeOld = qbh_r->cbMem;
wSize = wSizeOld + sizeof(TLP) + cchTitle;
bmk = GhResize(QDE_BMK(qde), 0, (LONG) wSize);
if (bmk == NULL) {
iBMKError |= iBMKOom;
return(iBMKFailure);
}
else
QDE_BMK(qde) = bmk;
}
qbh_r = PtrFromGh(QDE_BMK(qde));
if (qbh_r == (QBMKHDR_RAM) NULL) {
ASSERT(FALSE);
iRetVal = iBMKFailure;
goto error_return;
}
else {
qchT = (LPSTR)qbh_r + wSizeOld;
MoveMemory(qchT, &tlp, sizeof(TLP));
MoveMemory(qchT + sizeof(TLP), qchTitle, cchTitle);
qbh_r->cbMem = wSize;
qbh_r->cBookmarks += 1;
qbh_r->cbOffset = 0;
qbh_r->wVersion = wVersion;
/* Open the file; create if it doesn't exist
*/
hf = HfOpenHfs (hfsBM, nszFilename, fFSOpenReadWrite);
if (!hf)
{
if (RcGetFSError() == rcNoExists)
{
hf = HfCreateFileHfs (hfsBM, nszFilename, fFSOpenReadWrite);
}
}
if (!hf) {
SetBMKFSError();
goto error_return0;
}
// Create a disk header and write to file
lTimeStamp = qhhdr->lDateCreated;
QdiskhdrFromRam( &bh_d, qbh_r, lTimeStamp );
cbHeader = CB_BMKHDR(wVersion);
if (LcbWriteHf(hf, &bh_d, cbHeader) != cbHeader) {
SetBMKFSError();
RcAbandonHf( hf );
goto error_return0;
}
// Write the bookmark info at the end of the file.
LSeekHf(hf, 0L, wFSSeekEnd);
// REVIEW: could optimize to one write.
if (LcbWriteHf(hf, &tlp, sizeof(TLP)) != sizeof(TLP)
||
LcbWriteHf(hf, (LPVOID) qchTitle, (LONG) cchTitle) !=
(LONG) cchTitle) {
SetBMKFSError();
RcAbandonHf(hf);
goto error_return0;
}
if (rcSuccess != RcCloseHf(hf)
||
rcSuccess != RcFlushHfs(hfsBM, fFSCloseFile)) {
SetBMKFSError();
goto error_return0;
}
}
}
return(iRetVal);
error_return0:
qbh_r->cBookmarks -= 1;
qbh_r->cbMem = wSizeOld;
error_return:
return(iBMKFailure);
}
/*-----------------------------------------------------------------------------
* VOID OpenBMFS()
*
* Description:
* This function opens the BM file system if exists else creates one.
*
* Arguments:
* NULL
*
* Returns;
* Nothing
*-----------------------------------------------------------------------------*/
void STDCALL OpenBMFS(void)
{
FM fm;
ASSERT ( hfsBM == NULL );
// reset the error.
iBMKError=iBMKNoError;
fm = FmNewSystemFm(NULL, FM_BKMK);
if (!fm) {
// NOTE - hack alert
// Assume OOM, but also set iBMKFSError so it will be checked
// at the beginning of RcLoadBookmark().
iBMKError = iBMKOom | iBMKFSError;
return;
}
iBMKError |= iBMKReadWrite;
hfsBM = HfsOpenFm( fm, fFSOpenReadWrite );
if (hfsBM == NULL) {
if (RcGetFSError() == rcNoExists) {
hfsBM = HfsCreateFileSysFm(fm, (FS_PARAMS *) NULL );
}
else {
if (RcGetFSError() == rcNoPermission) {
hfsBM = HfsOpenFm(fm, fFSOpenReadOnly);
if (hfsBM != NULL)
iBMKError |= iBMKReadOnly;
}
}
}
if (hfsBM == NULL) {
SetBMKFSError();
iBMKError |= iBMKFSError;
}
DisposeFm(fm);
}
/*-----------------------------------------------------------------------------
* BOOL ChkBMFS()
*
* Description:
* This function checks if BMK read only or open error etc.
*
* Returns;
* True if proper
* FALSE otherwise
*-----------------------------------------------------------------------------*/
static BOOL STDCALL ChkBMFS(void)
{
BOOL err = TRUE;
if (iBMKError & iBMKReadOnly)
err = FALSE;
else if (iBMKError & iBMKOom)
err = FALSE;
else if (iBMKError & iBMKCorrupted)
err = FALSE;
else if (iBMKError & iBMKBadVersion)
err = FALSE;
else if (iBMKError & iBMKFSError)
err = FALSE;
return(err);
}
/***
returns:
0 if no error.
iBMKBadVersion if bad version
iBMKCorrupted if corrupted.
iBMKFSError if creation problem.
***/
int STDCALL IsErrorBMFS()
{
if (iBMKError & iBMKBadVersion)
return(iBMKBadVersion);
if (iBMKError & iBMKCorrupted)
return(iBMKCorrupted);
if (iBMKError & iBMKFSError)
return(iBMKFSError);
return(0);
}
/*-----------------------------------------------------------------------------
* SetBMKFSError()
*
* Description:
* This function prompts the error in FS and exits.
* Arguments:
* NULL
* Returns;
* NOTHING
*-----------------------------------------------------------------------------*/
static void STDCALL SetBMKFSError(void)
{
switch (RcGetFSError()) {
case rcDiskFull:
iBMKError |= iBMKDiskFull;
break;
case rcOutOfMemory:
iBMKError |= iBMKOom;
break;
case rcInvalid:
iBMKError |= iBMKCorrupted;
break;
case rcBadVersion:
iBMKError |= iBMKBadVersion;
break;
default:
iBMKError |= iBMKFSReadWrite;
break;
}
}
void STDCALL ResetBMKError()
{
iBMKError &= 0x7;
}
int STDCALL GetBMKError()
{
return(iBMKError);
}
/***************************************************************************\
*
- Function: QramhdrFromDisk( qbh_r, qbh_d, wVersion )
-
* Purpose: Convert a disk bookmark header to a memory version.
*
* ASSUMES
* args IN: qbh_r - pointer to a BMKHDR_RAM
* qbh_d - pointer to a valid BMKHDR_DISK
* wVersion - specify format of qbh_d
*
* PROMISES
* returns: qbh_r
* args OUT: qbh_r - values in qbh_d have been converted and copied
*
\***************************************************************************/
INLINE static QBMKHDR_RAM STDCALL QramhdrFromDisk(
QBMKHDR_RAM qbh_r,
QBMKHDR_DISK qbh_d,
WORD wVersion)
{
if (wVersion == wVersion3_0) {
qbh_r->cBookmarks = qbh_d->bmkhdr3_0.cBookmarks;
qbh_r->cbMem = qbh_d->bmkhdr3_0.cbFile
- sizeof( BMKHDR3_0 ) + sizeof( BMKHDR_RAM );
qbh_r->wVersion = wVersion3_0;
}
else {
qbh_r->cBookmarks = qbh_d->bmkhdr3_5.cBookmarks;
qbh_r->cbMem = qbh_d->bmkhdr3_5.cbFile
- sizeof( BMKHDR3_5 ) + sizeof( BMKHDR_RAM );
qbh_r->wVersion = qbh_d->bmkhdr3_5.wVersion;
}
qbh_r->cbOffset = 0;
return qbh_r;
}
/***************************************************************************\
*
- Function: QdiskhdrFromRam( qbh_d, qbh_r, lTimeStamp )
-
* Purpose: Convert a memory bookmark header to a disk version.
*
* ASSUMES
* args IN: qbh_d - pointer to a BMKHDR_DISK
* qbh_r - pointer to a valid BMKHDR_RAM
* wVersion - specify format of qbh_d
* lTimeStamp - timestamp of help file
*
* PROMISES
* returns: qbh_d
* args OUT: qbh_d - values in qbh_r have been converted and copied
*
\***************************************************************************/
INLINE static QBMKHDR_DISK STDCALL QdiskhdrFromRam(
QBMKHDR_DISK qbh_d,
QBMKHDR_RAM qbh_r,
LONG lTimeStamp )
{
if (qbh_r->wVersion == wVersion3_0) {
qbh_d->bmkhdr3_0.cBookmarks = qbh_r->cBookmarks;
qbh_d->bmkhdr3_0.cbFile = qbh_r->cbMem - sizeof( BMKHDR_RAM )
+ sizeof( BMKHDR3_0 );
qbh_d->bmkhdr3_0.cbOffset = 0;
}
else {
qbh_d->bmkhdr3_5.lTimeStamp = lTimeStamp;
qbh_d->bmkhdr3_5.wVersion = qbh_r->wVersion;
qbh_d->bmkhdr3_5.cBookmarks = qbh_r->cBookmarks;
qbh_d->bmkhdr3_5.cbFile = qbh_r->cbMem - sizeof( BMKHDR_RAM )
+ sizeof( BMKHDR3_5 );
}
return qbh_d;
}
/***************************************************************************\
*
- Function: HfOpenBookmarkFile( qde )
-
* Purpose: Open the bookmark file containing bookmarks for the
* current helpfile, if any.
*
* ASSUMES
* args IN: qde - FM and HHDR
* globals IN: hfsBM - open bookmark FS
* state IN:
*
* PROMISES
* returns: bookmarks exist: handle to open bookmark file
* no bookmarks: NULL
* error: NULL
* args OUT:
* globals OUT: iBMKError: contains error code if NULL returned
* state OUT:
* Side Effects:
* Notes:
* Bugs:
* +++
* Method:
* Notes:
*
\***************************************************************************/
INLINE static HF HfOpenBookmarkFile(QDE qde)
{
HF hf;
char nszFilename[ MAX_BMK_FILENAME ];
ASSERT(hfsBM != NULL);
BmkFilename(qde, nszFilename);
hf = HfOpenHfs(hfsBM, nszFilename, fFSOpenReadOnly);
if (!hf && RcGetFSError() != rcNoExists)
SetBMKFSError();
return hf;
}
/***************************************************************************\
*
- Function: BmkFilename( QDE qde, PSTR pszFilename )
-
* Purpose: Return the name of the bookmark file corresponding
* to the current help file.
*
* ASSUMES
* args IN: qde - FM and HHDR
* pszFilename - pointer to caller's near buffer for filename
* MAX_BMK_FILENAME bytes long
* globals IN:
* state IN:
*
* PROMISES
* args OUT: pszFilename - contains name of the bookmark file
* corresponding to current help file.
* +++
*
* Method: 3.0 bookmarks for helpfile d:\path\base.ext are stored
* in a file named "base". The 3.5 bookmark file name
* would be "baseXXXXXXXX", where XXXXXXXX is the timestamp
* of the help file, in hex.
* 2 * sizeof( LONG ) characters are needed to print a LONG
* in hex because each byte takes 2 characters.
*
* Note: REVIEW: what about upper/lower case for HPFS filenames?
*
\***************************************************************************/
static void BmkFilename(QDE qde, PSTR pszFilename)
{
GetFmParts(QDE_FM(qde), pszFilename, PARTBASE);
if (QDE_HHDR(qde).wVersionNo != wVersion3_0)
wsprintf(pszFilename + strlen(pszFilename), "%x", QDE_HHDR(qde).lDateCreated);
}
/* EOF */