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.
 
 
 
 
 
 

893 lines
19 KiB

// Hilite.c -- Code to drive the FTSrch hilite APIs
#include "help.h"
// #include "FrTypes.h"
#include "FrStuff.h"
// #include "FrParagp.h"
#include "FcPriv.h"
// Variables to support hilites from the Find tab:
static CHAR achMemberHilite[cchWindowMemberMax];
static char szFNameHilite[MAX_PATH];
static VA vaHilite= { vaNil }; // vaNil for no hilites;
// == vaNSR or vaSR when hilites exist
static HANDLE haHilites; // handle for results from HILITER
static HANDLE haHelpHilites; // handle for results mapped into HELPHILITE form
static HILITE *paHilites; // address of results from HILITER
static HELPHILITE *paHelpHilites; // address of results mapped into HELPHILITE form
static UINT cHilites; // number of hilites
// Variables used to map the HILITE array into the HELPHILITE array:
static HILITE *pHilite; // Points to the current HILITE item
static HELPHILITE *pHelpHilite; // Points to the current HELPHILITE item
static UINT cHilitesLeft; // Number of HILITE items left to map
static BOOL fScanningForStart; // True when we're looking for a text
// segment containing the base offset
// of a HILITE. False when we're looking
// for the limit offset.
#ifdef _DEBUG
#define HeapChecker() lcHeapCheck()
#else // _DEBUG
#define HeapChecker()
#endif // _DEBUG
BOOL STDCALL HilitesDefined()
{
return vaHilite.dword != vaNil;
}
BOOL IsHiliteWindow(QDE qde)
{
PSTR pszMemberName;
int iWnd;
if (!HilitesDefined()) return FALSE;
if (hwndNote) return FALSE; // If hwndNote is non-null, we're in a popup window
for (iWnd= 0; iWnd < MAX_WINDOWS; ++iWnd)
if ( ahwnd[iWnd].hwndTopic == qde->hwnd
|| ahwnd[iWnd].hwndTitle == qde->hwnd
)
{
pszMemberName= ahwnd[iWnd].pszMemberName;
if (!pszMemberName) return FALSE;
return !WCmpiSz(achMemberHilite, pszMemberName);
}
return FALSE;
}
BOOL STDCALL HasTopicChanged(QDE qde)
{
VA vaDE;
if (!IsHiliteWindow(qde)) return FALSE;
if (WCmpiSz(szFNameHilite, PszFromGh(QDE_FM(qde)))) return TRUE; // Same HLP file?
ASSERT(qde->top.mtop.vaNSR.dword != vaNil || qde->top.mtop.vaSR.dword != vaNil);
vaDE= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
: qde->top.mtop.vaSR;
return vaDE.dword != vaHilite.dword; // Same address within the HLP file?
}
void STDCALL CheckForTopicChanges(QDE qde)
{
if (vaHilite.dword == vaNil) return;
if (HasTopicChanged(qde))
DiscardHiliteInformation();
}
static BOOL STDCALL ScanThisTopic(QDE qde);
static void STDCALL InitScanBuffer(BOOL fSendToScanner);
static void STDCALL DisconnectScanBuffer();
void STDCALL CreateHiliteInformation(QDE qde)
{
int c;
PHILITE phlSrc, phlDest;
BOOL fScanned;
HeapChecker();
if (vaHilite.dword != vaNil) DiscardHiliteInformation();
HeapChecker();
InitScanBuffer(TRUE);
HeapChecker();
fScanned= ScanThisTopic(qde);
HeapChecker();
DisconnectScanBuffer();
HeapChecker();
if (!fScanned) return;
ASSERT(!cHilites);
ASSERT(!haHilites);
ASSERT(!haHelpHilites);
cHilites= pCountHilites(GetHiliter(), 0, -1);
if (!cHilites) return;
haHilites= GhAlloc(LMEM_FIXED, cHilites * sizeof(HILITE));
HeapChecker();
if (!haHilites) goto resource_limited;
paHilites= (PHILITE) PtrFromGh(haHilites);
if (0 > pQueryHilites(GetHiliter(), 0, -1, cHilites, paHilites))
goto resource_limited;
HeapChecker();
if (cHilites > 1)
{
// The hilite array may contain overlapping hilites.
// The loop below looks for overlaps and consolidates
// them.
for (c= cHilites, phlDest= paHilites, phlSrc= paHilites + 1;
--c;
)
{
ASSERT(phlSrc->base >= phlDest->base);
if (phlDest->limit > phlSrc->base)
{
ASSERT(phlSrc->limit >= phlDest->limit);
phlDest->limit = (phlSrc++)->limit;
}
else *(++phlDest)= *phlSrc++;
}
cHilites= 1 + (phlDest - paHilites);
HeapChecker();
}
cHilitesLeft= cHilites;
haHelpHilites= GhAlloc(GMEM_FIXED, cHilites * sizeof(HELPHILITE));
HeapChecker();
if (!haHelpHilites) goto resource_limited;
paHelpHilites= (PHELPHILITE) PtrFromGh(haHelpHilites);
HeapChecker();
InitScanBuffer(FALSE);
HeapChecker();
fScanned= ScanThisTopic(qde);
HeapChecker();
FreeGh(haHilites); haHilites= NULL; pHelpHilite= NULL; pHilite= paHilites= NULL;
HeapChecker();
if (!fScanned) goto resource_limited;
lstrcpy(achMemberHilite, ahwnd[iCurWindow].pszMemberName);
lstrcpy(szFNameHilite, PszFromGh(QDE_FM(qde)));
vaHilite= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
: qde->top.mtop.vaSR;
return;
resource_limited:
// If we don't have enough memory to construct the highlight structures
// we just deallocate the partial results and set the hilite count to
// zero.
HeapChecker();
if (haHelpHilites) { FreeGh(haHelpHilites); haHelpHilites = NULL; }
if (haHilites ) { FreeGh(haHilites ); haHilites = NULL; }
HeapChecker();
pHilite = paHilites = NULL;
pHelpHilite = paHelpHilites = NULL;
cHilitesLeft = cHilites = 0;
}
void STDCALL DiscardHiliteInformation()
{
int iWnd;
ASSERT(HilitesDefined());
for (iWnd= 0; iWnd < MAX_WINDOWS; ++iWnd)
if ( ahwnd[iWnd].pszMemberName
&& !WCmpiSz(achMemberHilite, ahwnd[iWnd].pszMemberName)
)
{
ASSERT(ahwnd[iWnd].hwndTopic);
if (ahwnd[iWnd].hwndTopic)
InvalidateRect(ahwnd[iWnd].hwndTopic, NULL, TRUE);
if (ahwnd[iWnd].hwndTitle)
InvalidateRect(ahwnd[iWnd].hwndTitle, NULL, TRUE);
break;
}
achMemberHilite[0] = 0;
szFNameHilite[0] = 0;
vaHilite.dword= vaNil;
ASSERT(!haHilites && !paHilites && !pHilite && !pHelpHilite);
HeapChecker();
if (haHelpHilites)
{
FreeGh(haHelpHilites);
haHelpHilites = NULL;
paHelpHilites = NULL;
cHilites = 0;
}
HeapChecker();
}
UINT STDCALL GetHilites(QDE qde, PHELPHILITE *ppHelpHilites)
{
if (!paHelpHilites || !cHilites) return 0;
if (!IsHiliteWindow(qde)) return 0;
if (HasTopicChanged(qde))
{
DiscardHiliteInformation();
return NULL;
}
*ppHelpHilites= paHelpHilites;
return cHilites;
}
#define COLLECT_BUFFER 4096
static BYTE ScanBuffer[COLLECT_BUFFER];
static PSTR pszCollect;
static UINT iCharSet;
static BOOL fPendingSpace;
static int cbScanned;
static int cbCollect;
static void STDCALL InitScanBuffer(BOOL fSendToScanner)
{
if (pszCollect) DisconnectScanBuffer();
pszCollect = fSendToScanner? ScanBuffer : NULL;
cbCollect = 0;
cbScanned = 0;
iCharSet = 0;
fPendingSpace = FALSE;
ASSERT(pClearDisplayText);
if (fSendToScanner) pClearDisplayText(GetHiliter());
else
{
pHilite = paHilites;
pHelpHilite = paHelpHilites;
cHilitesLeft = cHilites;
fScanningForStart = TRUE;
}
}
static void STDCALL FlushToScanner();
static void STDCALL DisconnectScanBuffer()
{
FlushToScanner();
pszCollect = NULL;
}
static void STDCALL FlushToScanner()
{
if (cbCollect)
pScanDisplayText(GetHiliter(), pszCollect, cbCollect, iCharSet, lcid);
cbCollect= 0;
}
// The QueueForScanner routine processes text from the display environment.
// Processing happens in two phases. During the first phase the text is passed
// to the HILITER. In that phase the explicit result from QueueForScanner is
// ignored. During the second phase we scan the text again to map an array of
// HILITES into an array of HELPHILITES. In the second phase the explicit result
// from QueueForScanner is TRUE when all the elements of the HILITES array have
// been mapped into the HELPHILITES array.
static BOOL STDCALL QueueForScanner(PSTR *ppszText, UINT charset, VA vaBase, int ichBase)
{
int cbBase;
PSZ pszText= *ppszText;
UINT cbText = strlen(pszText);
*ppszText = pszText + cbText;
if (fPendingSpace) cbScanned++;
cbBase= cbScanned;
cbScanned += cbText;
// This routine is used for two purposes. When pszCollect is non-NULL
// we're passing the topic text along to the Hiliter. When it's NULL,
// we're remapping the HILITE array into the HELPHILITE array.
if (!pszCollect)
{
fPendingSpace= FALSE;
for (;;)
{
if (!cHilitesLeft) return TRUE;
if (fScanningForStart)
{
if (pHilite->base >= cbScanned) return FALSE;
// ASSERT(pHilite->base >= cbBase);
pHelpHilite->vaBase = vaBase;
pHelpHilite->ichBase = ichBase + pHilite->base - cbBase;
if (pHilite->limit > cbScanned)
{
fScanningForStart= FALSE;
return FALSE;
}
pHelpHilite->vaLimit = vaBase;
pHelpHilite->ichLimit = ichBase + pHilite->limit - cbBase;
++pHelpHilite;
++pHilite;
--cHilitesLeft;
continue;
}
if (pHilite->limit > cbScanned) return FALSE;
pHelpHilite->vaLimit = vaBase;
pHelpHilite->ichLimit = ichBase + pHilite->limit - cbBase;
fScanningForStart = TRUE;
++pHelpHilite;
++pHilite;
--cHilitesLeft;
continue;
}
}
if (charset != iCharSet)
{
FlushToScanner();
iCharSet= charset;
}
if (cbText + cbCollect + (fPendingSpace? 1 : 0) > COLLECT_BUFFER)
FlushToScanner();
if (fPendingSpace)
{
pszCollect[cbCollect++] = ' ';
fPendingSpace= FALSE;
}
while (cbText)
{
int cbChunk= cbText;
if (cbChunk > COLLECT_BUFFER - cbCollect)
cbChunk = COLLECT_BUFFER - cbCollect;
cbText -= cbChunk;
CopyMemory(pszCollect + cbCollect, pszText, cbChunk);
cbCollect += cbChunk;
pszText += cbChunk;
if (cbCollect == COLLECT_BUFFER)
FlushToScanner();
}
return FALSE;
}
static BOOL fTitleSeen;
static BOOL bSYS;
static BOOL bSYSFirst;
static BOOL STDCALL NextFTSString(QDE qde, LPSTR pszText, LPSTR *ppCmd,
int* pCharSet, VA vaBase, PCSTR pszEnd)
{
char chCmd;
MOBJ mobj;
MOPG mopg;
BOOL bProcessCell = FALSE;
short int iCell;
BYTE CharSetNew;
LPSTR pszBase= pszText;
if (*pszText)
QueueForScanner(&pszText, *pCharSet, vaBase, pszText - pszBase);
ASSERT(*pszText == 0x00);
while (pszText < pszEnd) {
while (*pszText == chCommand) {
// Side by side paragraph has the following embedded structure:
// INT16 cell number;
// MOBJ;
// MOPG;
if (bSYS && bSYSFirst)
{
bSYSFirst = FALSE;
bProcessCell = TRUE;
#ifdef _X86_
iCell = *((short int *) *ppCmd);
#else
{
UNALIGNED short int *pTemp;
pTemp = (short int *)*ppCmd;
iCell = *pTemp;
}
#endif
(*ppCmd) += 2;
if (iCell < 0)
return TRUE;
#ifdef _X86_
(*ppCmd) += CbUnpackMOBJ(&mobj, *ppCmd);
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd);
#else
(*ppCmd) += CbUnpackMOBJ(&mobj, (void *) *ppCmd, QDE_ISDFFTOPIC(qde));
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd, QDE_ISDFFTOPIC(qde));
#endif
}
// do
// {
chCmd = **ppCmd;
switch((0x00FF & chCmd))
{
case bNewLine:
fPendingSpace = TRUE;
(*ppCmd)++;
break;
case bNewPara:
fPendingSpace = TRUE;
(*ppCmd)++;
break;
case bTab:
fPendingSpace = TRUE;
(*ppCmd)++;
break;
case bEndHotspot:
(*ppCmd)++;
break;
case bBlankLine:
fPendingSpace = TRUE;
*ppCmd += 3;
break;
case bWordFormat:
(*ppCmd)++;
#ifdef _X86_
CharSetNew = GetCharset(qde, (*((INT16*)*ppCmd))) & 0x000000ff;
#else
{
UNALIGNED INT16 *pTemp;
pTemp = (INT16*) *ppCmd;
CharSetNew = GetCharset(qde, *pTemp) & 0x000000ff;
}
#endif
if (CharSetNew != *pCharSet)
{
FlushToScanner();
*pCharSet= CharSetNew;
}
*ppCmd += 2;
break;
case bWrapObjLeft:
case bWrapObjRight:
case bInlineObject:
fPendingSpace = TRUE;
(*ppCmd)++;
#ifdef _X86_
*ppCmd += CbUnpackMOBJ(&mobj, (void *) *ppCmd);
#else
*ppCmd += CbUnpackMOBJ(&mobj, (void *) *ppCmd,
QDE_ISDFFTOPIC(qde));
#endif
*ppCmd += (INT16) mobj.lcbSize;
break;
case bEnd:
(*ppCmd)++;
// fPendingSpace= TRUE;
if (bSYS)
{
bProcessCell = TRUE;
#ifdef _X86_
iCell = *((short int *) *ppCmd);
#else
{
UNALIGNED short int *pTemp;
pTemp = (short int *)*ppCmd;
iCell = *pTemp;
}
#endif
(*ppCmd) += 2;
if (iCell < 0)
return TRUE;
#ifdef _X86_
(*ppCmd) += CbUnpackMOBJ(&mobj, *ppCmd);
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd);
#else
(*ppCmd) += CbUnpackMOBJ(&mobj, (void *) *ppCmd, QDE_ISDFFTOPIC(qde));
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd, QDE_ISDFFTOPIC(qde));
#endif
}
if (bProcessCell)
bProcessCell = FALSE;
else
return TRUE;
break;
default:
if (FShortHotspot(**ppCmd))
{
*ppCmd += 5;
}
else if (FLongHotspot(**ppCmd))
{
(*ppCmd)++;
#ifdef _X86_
*ppCmd += 2 + *((INT16*)*ppCmd);
#else
{UNALIGNED INT16 *pTemp;
pTemp = (INT16*)*ppCmd;
*ppCmd += 2 + *pTemp;
}
#endif
}
else
{
ASSERT(FALSE);
return TRUE;
}
break;
}
// } while (bProcessCell);
pszText++;
}
if (pszText) QueueForScanner(&pszText, *pCharSet, vaBase, pszText - pszBase);
}
return TRUE;
}
enum {
TABTYPELEFT,
TABTYPERIGHT,
TABTYPECENTER,
TABTYPEDECIMAL
};
#ifdef _X86_
static PBYTE STDCALL ScanTopic(LPSTR lpData, QFCINFO qfcinfo, MTOP* pmtop)
#else
static PBYTE STDCALL ScanTopic(LPSTR lpData, QFCINFO qfcinfo, MTOP* pmtop, QDE qde)
#endif
{
MOBJ mobj;
int iTopic;
QMSBS qmsbs;
#ifndef _X86_
MTOP mtop;
#endif
for(;;) {
#ifdef _X86_
lpData += CbUnpackMOBJ(&mobj, (QV) lpData);
#else
lpData += CbUnpackMOBJ(&mobj, (QV) lpData,QDE_ISDFFTOPIC(qde));
#endif
iTopic = 0x00FF & mobj.bType;
bSYS = FALSE;
bSYSFirst = FALSE;
switch (iTopic)
{
case bTypeSbys:
case bTypeSbysCounted:
if (pmtop)
return lpData;
bSYS = TRUE;
bSYSFirst = TRUE;
qmsbs = (QMSBS) lpData;
lpData += 2;
if (!qmsbs->fAbsolute)
{
lpData += 2;
}
lpData += qmsbs->bcCol * sizeof(MCOL);
return(lpData);
default:
if (pmtop)
ZeroMemory(pmtop, sizeof(MTOP));
return(NULL);
break;
case bTypeParaGroup:
case bTypeParaGroupCounted:
{
MOPG mopg;
MPFG mpfg;
LPSTR lpStart = lpData;
int iTab;
if (pmtop)
return lpData;
lpData = QVSkipQGE(lpData, (QL) &(mopg.libText));
#ifdef _X86_
mpfg = *((QMPFG) lpData);
#else
MoveMemory(&mpfg, lpData, sizeof(MPFG));
#endif
lpData = (LPSTR) (((QMPFG) lpData) + 1);
if (mpfg.rgf.fMoreFlags)
{
lpData = QVSkipQGE(lpData, (QL) &(mopg.lMoreFlags));
}
if (mpfg.rgf.fSpaceOver)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.ySpaceOver));
}
if (mpfg.rgf.fSpaceUnder)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.ySpaceUnder));
}
if (mpfg.rgf.fLineSpacing)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.yLineSpacing));
}
if (mpfg.rgf.fLeftIndent)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &mopg.xLeftIndent);
}
if (mpfg.rgf.fRightIndent)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xRightIndent);
}
if (mpfg.rgf.fFirstIndent)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xFirstIndent);
}
mopg.xTabSpacing = 72;
if (mpfg.rgf.fTabSpacing)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xTabSpacing);
}
if (mpfg.rgf.fBoxed)
{
mopg.mbox = *((UNALIGNED MBOX *)lpData);
#ifdef _X86_
lpData = (LPSTR) (((QMBOX)lpData) + 1);
#else
lpData = (QB)lpData + 3;
#endif
}
if (mpfg.rgf.fTabs)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &mopg.cTabs);
}
else
mopg.cTabs = 0;
for (iTab = 0; iTab < mopg.cTabs; iTab++)
{
lpData = QVSkipQGA(lpData, (QI) &mopg.rgtab[iTab].x);
if (mopg.rgtab[iTab].x & 0x4000)
lpData = QVSkipQGA(lpData, (QI) &mopg.rgtab[iTab].wType);
else
mopg.rgtab[iTab].wType = TABTYPELEFT;
mopg.rgtab[iTab].x = mopg.rgtab[iTab].x & 0xBFFF;
}
}
return(lpData);
break;
case bTypeTopic:
if (pmtop) { // all we wanted was MTOP structure
MoveMemory(pmtop, lpData, sizeof(MTOP));
return NULL;
}
else
#ifdef _X86_
pmtop = (MTOP*) lpData;
#else
{
MoveMemory(&mtop, lpData, sizeof(MTOP));
pmtop = & mtop;
}
#endif
lpData += sizeof(MTOP);
fTitleSeen = TRUE;
return(NULL);
}
}
}
static BOOL STDCALL ForageTopic(QDE qde, VA vaNext)
{
static DB db;
int wErr;
HFC hfc = NULL;
LPSTR lpCmd;
LPSTR lpText;
DWORD dwCmd;
int cbAnimate = 0;
QFCINFO qfcinfo;
iCharSet = defcharset;
fTitleSeen = FALSE;
while (!fTitleSeen && (hfc = GetQFCINFO(qde, vaNext, &wErr)) != NULL)
{
qfcinfo = (QFCINFO) PtrFromGh(hfc);
/*
* In order for WinHelp to be able to jump to this topic,
* vaCurrent must be set to vaNext. Don't ask me why -- but it works.
* Same VA is used in History and Bookmark jumps. [ralphw]
*/
vaNext = qfcinfo->vaNext;
#ifdef _X86_
lpCmd = ScanTopic(((LPSTR) qfcinfo) + sizeof(FCINFO), qfcinfo, NULL);
#else
lpCmd = ScanTopic(((LPSTR) qfcinfo) + sizeof(FCINFO), qfcinfo, NULL, qde);
#endif
if (lpCmd)
{
lpText = ((LPSTR) qfcinfo) + qfcinfo->ichText;
dwCmd = lpText - lpCmd;
if (!NextFTSString(qde, lpText, &lpCmd, &iCharSet, qfcinfo->vaCurr,
lpText + qfcinfo->lcbText
)
)
{
FreeGh(hfc); hfc= NULL;
return FALSE;
}
}
FreeGh(hfc); hfc= NULL;
}
return TRUE;
}
static BOOL STDCALL ScanThisTopic(QDE qde)
{
HDE hde = NULL;
VA vaHilite;
BOOL fRet;
hde = HdeCreate(NULL, qde, deTopic);
if (!hde) return FALSE;
vaHilite= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
: qde->top.mtop.vaSR;
fRet = ForageTopic(QdeFromGh(hde), vaHilite);
ASSERT(hde);
DestroyHde(hde);
return fRet;
}