480 lines
14 KiB
C
480 lines
14 KiB
C
/*-------------------------------------------------------------------------
|
|
| frconv.c |
|
|
| Microsoft Confidential |
|
|
| |
|
|
| mattb 8/8/89 |
|
|
|-------------------------------------------------------------------------|
|
|
| This file contains predeclarations and definitions for the compressed |
|
|
| data structure management code. |
|
|
-------------------------------------------------------------------------*/
|
|
|
|
#include "help.h"
|
|
#pragma hdrstop
|
|
|
|
#define DECOMPRESS
|
|
|
|
static int STDCALL FVerifyQMOPG(QMOPG qmopg);
|
|
|
|
/*-------------------------------------------------------------------------
|
|
| The compressed data structures are used to reduce the size of our help |
|
|
| files. We use six basic kinds: |
|
|
| Type Input value Storage size Min Max |
|
|
| GA unsigned int 1 or 2 bytes 0 7FFF |
|
|
| GB unsigned long 2 or 4 bytes 0 7FFFFFFF |
|
|
| GC unsigned long 3 bytes 0 FFFFFF |
|
|
| GD signed int 1 or 2 bytes C000 3FFF |
|
|
| GE signed long 2 or 4 bytes C0000000 3FFFFFFF |
|
|
| GF signed long 3 bytes C00000 3FFFFF |
|
|
| |
|
|
| For more details, set the compressed data structures document. |
|
|
| |
|
|
| There are two kinds of procedures here: compression procedures and |
|
|
| decompression procedures. Only the decompression procedures will be |
|
|
| generated unless COMPRESS is defined. |
|
|
| |
|
|
| Procedures in this file rely on data structure checkers elsewhere in |
|
|
| help. |
|
|
-------------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------------
|
|
| CbUnpackMOPG(qde, qmopg, qv) |
|
|
| |
|
|
| Purpose: Unpacks an MOPG data structure. |
|
|
-------------------------------------------------------------------------*/
|
|
|
|
#ifdef _X86_
|
|
int STDCALL CbUnpackMOPG(QDE qde, QMOPG qmopg, void* qv)
|
|
#else //_X86_
|
|
int STDCALL CbUnpackMOPG(QDE qde, QMOPG qmopg, void* qv, int isdff)
|
|
#endif // _X86_
|
|
{
|
|
void* qvFirst = qv;
|
|
MPFG mpfg;
|
|
int iTab;
|
|
#ifndef _X86_
|
|
QB qb;
|
|
#endif // _X86_
|
|
|
|
#ifdef MAGIC
|
|
qmopg->bMagic = *((PBYTE)qv);
|
|
qv = (((PBYTE)qv) + 1);
|
|
Assert(qmopg->bMagic == bMagicMOPG);
|
|
#endif //MAGIC
|
|
|
|
#ifdef _X86_
|
|
qv = QVSkipQGE(qv, (QL)&qmopg->libText);
|
|
|
|
mpfg = *((QMPFG)qv);
|
|
qv = (((QMPFG)qv) + 1);
|
|
#else
|
|
/* Map the SDFF portion (currently one field) and then do the
|
|
* rest ourselves.
|
|
*/
|
|
qb = (QB)qv;
|
|
qb += LcbMapSDFF(isdff, SE_MOPG, (QV)qmopg, qb);
|
|
qb += LcbQuickMapSDFF(isdff, TE_BITF16, (QV)&mpfg, qb);
|
|
qb += LcbQuickMapSDFF(isdff, TE_BITF16, (QV)&mpfg.rgf, qb);
|
|
#endif // _X86_
|
|
|
|
/* REVIEW */
|
|
qmopg->fStyle = mpfg.fStyle;
|
|
ASSERT(!qmopg->fStyle);
|
|
qmopg->fMoreFlags = mpfg.rgf.fMoreFlags;
|
|
ASSERT(!qmopg->fMoreFlags);
|
|
qmopg->fBoxed = mpfg.rgf.fBoxed;
|
|
qmopg->wJustify = mpfg.rgf.wJustify;
|
|
qmopg->fSingleLine = mpfg.rgf.fSingleLine;
|
|
|
|
#ifdef BIDI
|
|
qmopg->wRtlReading = mpfg.rgf.fRtlReading;
|
|
#endif
|
|
|
|
#ifdef _X86_
|
|
if (mpfg.rgf.fMoreFlags)
|
|
qv = QVSkipQGE(qv, (QL)&qmopg->lMoreFlags);
|
|
else
|
|
qmopg->lMoreFlags = 0;
|
|
|
|
if (mpfg.rgf.fSpaceOver) {
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->ySpaceOver);
|
|
qmopg->ySpaceOver = YPixelsFromPoints(qde, qmopg->ySpaceOver);
|
|
}
|
|
else
|
|
qmopg->ySpaceOver = 0;
|
|
|
|
if (mpfg.rgf.fSpaceUnder) {
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->ySpaceUnder);
|
|
qmopg->ySpaceUnder = YPixelsFromPoints(qde, qmopg->ySpaceUnder);
|
|
}
|
|
else
|
|
qmopg->ySpaceUnder = 0;
|
|
|
|
if (mpfg.rgf.fLineSpacing) {
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->yLineSpacing);
|
|
|
|
ASSERT(qmopg->yLineSpacing);
|
|
|
|
if (qmopg->yLineSpacing < 0) qmopg->yLineSpacing -= cntFlags.iFontAdjustment;
|
|
else qmopg->yLineSpacing += cntFlags.iFontAdjustment;
|
|
|
|
qmopg->yLineSpacing = YPixelsFromPoints(qde, qmopg->yLineSpacing);
|
|
}
|
|
else qmopg->yLineSpacing = 0;
|
|
|
|
if (mpfg.rgf.fLeftIndent) {
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->xLeftIndent);
|
|
qmopg->xLeftIndent = XPixelsFromPoints(qde, qmopg->xLeftIndent);
|
|
}
|
|
else
|
|
qmopg->xLeftIndent = 0;
|
|
|
|
if (mpfg.rgf.fRightIndent) {
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->xRightIndent);
|
|
qmopg->xRightIndent = XPixelsFromPoints(qde, qmopg->xRightIndent);
|
|
}
|
|
else
|
|
qmopg->xRightIndent = 0;
|
|
|
|
if (mpfg.rgf.fFirstIndent) {
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->xFirstIndent);
|
|
qmopg->xFirstIndent = XPixelsFromPoints(qde, qmopg->xFirstIndent);
|
|
}
|
|
else
|
|
qmopg->xFirstIndent = 0;
|
|
|
|
if (mpfg.rgf.fTabSpacing)
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->xTabSpacing);
|
|
else
|
|
qmopg->xTabSpacing = 72;
|
|
qmopg->xTabSpacing = XPixelsFromPoints(qde, qmopg->xTabSpacing);
|
|
|
|
if (mpfg.rgf.fBoxed) {
|
|
qmopg->mbox = *((QMBOX)qv);
|
|
qv = (((QMBOX)qv) + 1);
|
|
}
|
|
|
|
if (mpfg.rgf.fTabs)
|
|
qv = QVSkipQGD(qv, (QI)&qmopg->cTabs);
|
|
else
|
|
qmopg->cTabs = 0;
|
|
|
|
for (iTab = 0; iTab < qmopg->cTabs; iTab++) {
|
|
qv = QVSkipQGA(qv, (QI)&qmopg->rgtab[iTab].x);
|
|
if (qmopg->rgtab[iTab].x & 0x4000)
|
|
qv = QVSkipQGA(qv, (QI)&qmopg->rgtab[iTab].wType);
|
|
else
|
|
qmopg->rgtab[iTab].wType = wTabTypeLeft;
|
|
qmopg->rgtab[iTab].x = qmopg->rgtab[iTab].x & 0xBFFF;
|
|
qmopg->rgtab[iTab].x = XPixelsFromPoints(qde, qmopg->rgtab[iTab].x);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
FVerifyQMOPG(qmopg);
|
|
#endif // DEBUG
|
|
|
|
return(((PBYTE) qv - (PBYTE) qvFirst));
|
|
#else // _X86_
|
|
if (mpfg.rgf.fMoreFlags)
|
|
qb += LcbQuickMapSDFF(isdff, TE_GE, (QL)&qmopg->lMoreFlags, qb);
|
|
else
|
|
qmopg->lMoreFlags = 0;
|
|
|
|
if (mpfg.rgf.fSpaceOver)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->ySpaceOver, qb);
|
|
qmopg->ySpaceOver = YPixelsFromPoints(qde, qmopg->ySpaceOver);
|
|
}
|
|
else
|
|
qmopg->ySpaceOver = 0;
|
|
|
|
if (mpfg.rgf.fSpaceUnder)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->ySpaceUnder, qb);
|
|
qmopg->ySpaceUnder = YPixelsFromPoints(qde, qmopg->ySpaceUnder);
|
|
}
|
|
else
|
|
qmopg->ySpaceUnder = 0;
|
|
|
|
if (mpfg.rgf.fLineSpacing)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->yLineSpacing, qb);
|
|
qmopg->yLineSpacing = YPixelsFromPoints(qde, qmopg->yLineSpacing);
|
|
}
|
|
else
|
|
qmopg->yLineSpacing = 0;
|
|
|
|
if (mpfg.rgf.fLeftIndent)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->xLeftIndent, qb);
|
|
qmopg->xLeftIndent = XPixelsFromPoints(qde, qmopg->xLeftIndent);
|
|
}
|
|
else
|
|
qmopg->xLeftIndent = 0;
|
|
|
|
if (mpfg.rgf.fRightIndent)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->xRightIndent, qb);
|
|
qmopg->xRightIndent = XPixelsFromPoints(qde, qmopg->xRightIndent);
|
|
}
|
|
else
|
|
qmopg->xRightIndent = 0;
|
|
|
|
if (mpfg.rgf.fFirstIndent)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->xFirstIndent, qb);
|
|
qmopg->xFirstIndent = XPixelsFromPoints(qde, qmopg->xFirstIndent);
|
|
}
|
|
else
|
|
qmopg->xFirstIndent = 0;
|
|
|
|
if (mpfg.rgf.fTabSpacing)
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->xTabSpacing, qb);
|
|
else
|
|
qmopg->xTabSpacing = 72;
|
|
qmopg->xTabSpacing = XPixelsFromPoints(qde, qmopg->xTabSpacing);
|
|
|
|
if (mpfg.rgf.fBoxed)
|
|
{
|
|
qb += LcbQuickMapSDFF(isdff, TE_BITF16, (QL)&qmopg->mbox, qb);
|
|
qb += LcbQuickMapSDFF(isdff, TE_BYTE, (QB)&qmopg->mbox.bUnused, qb);
|
|
}
|
|
|
|
if (mpfg.rgf.fTabs)
|
|
qb += LcbQuickMapSDFF(isdff, TE_GD, (QI)&qmopg->cTabs, qb);
|
|
else
|
|
qmopg->cTabs = 0;
|
|
|
|
for (iTab = 0; iTab < qmopg->cTabs; iTab++)
|
|
{
|
|
qb += LcbMapSDFF(isdff, SE_TAB, (QI)&qmopg->rgtab[iTab].x, qb);
|
|
if (qmopg->rgtab[iTab].x & 0x4000)
|
|
qb += LcbQuickMapSDFF(isdff, TE_GA, (QI)&qmopg->rgtab[iTab].wType, qb);
|
|
else
|
|
qmopg->rgtab[iTab].wType = wTabTypeLeft;
|
|
qmopg->rgtab[iTab].x = qmopg->rgtab[iTab].x & 0xBFFF;
|
|
qmopg->rgtab[iTab].x = XPixelsFromPoints(qde, qmopg->rgtab[iTab].x);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
FVerifyQMOPG(qmopg);
|
|
#endif // DEBUG
|
|
|
|
return((int)((PBYTE) ((QB)qb - (QB)qvFirst)));
|
|
#endif // else _X86_
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
| CbUnpackMOBJ(qmobj, qv) |
|
|
| |
|
|
| Purpose: Unpack an MOBJ data structure. |
|
|
-------------------------------------------------------------------------*/
|
|
#ifdef _X86_
|
|
int STDCALL CbUnpackMOBJ(QMOBJ qmobj, void* qv)
|
|
{
|
|
QV qvFirst = qv;
|
|
|
|
/*
|
|
* Topic FCs are not packed, because the topic size needs to be
|
|
* backpatched by the compiler.
|
|
*/
|
|
|
|
if (((QMOBJ) qv)->bType == bTypeTopic ||
|
|
((QMOBJ) qv)->bType == bTypeTopicCounted) {
|
|
qmobj->bType = *((PBYTE)qv);
|
|
qv = (((PBYTE)qv) + 1);
|
|
qmobj->lcbSize = *((QL)qv);
|
|
qv = (((QL)qv) + 1);
|
|
/*
|
|
* If FC is uncounted, then it doesn't contain the last field in the
|
|
* MOBJ, and we need to set wObjInfo to 0. Note that we cannot simply
|
|
* copy the MOBJ structure because it is longer in Help 3.5: the MOBJ for
|
|
* a Help 3.0 file (and any structure in general) may happen right at the
|
|
* end of a segment. (See H3.5 739)
|
|
*/
|
|
|
|
if (qmobj->bType == bTypeTopicCounted)
|
|
{
|
|
qmobj->wObjInfo = *((QW)qv);
|
|
qv = (((QW)qv) + 1);
|
|
}
|
|
else
|
|
qmobj->wObjInfo = 0;
|
|
return (((PBYTE) qv - (PBYTE) qvFirst));
|
|
}
|
|
|
|
qmobj->bType = *((PBYTE)qv);
|
|
qv = (((PBYTE)qv) + 1);
|
|
qv = QVSkipQGE(qv, (QL)&qmobj->lcbSize);
|
|
ASSERT(qmobj->lcbSize >= 0);
|
|
|
|
if (qmobj->bType > MAX_UNCOUNTED_OBJ_TYPE)
|
|
qv = QVSkipQGA(qv, (QW)&qmobj->wObjInfo);
|
|
else
|
|
qmobj->wObjInfo = 0;
|
|
|
|
return(((PBYTE)qv - (PBYTE)qvFirst));
|
|
#else
|
|
int STDCALL CbUnpackMOBJ(QMOBJ qmobj, void* qvSrc, int isdff)
|
|
{
|
|
BYTE bType = *(QB)qvSrc;
|
|
LONG lcbRet = 0L;
|
|
|
|
if (bType == bTypeTopic)
|
|
{
|
|
lcbRet = LcbMapSDFF(isdff, SE_MOBJTOPICUNCOUNTED, (QV)qmobj, qvSrc);
|
|
qmobj->wObjInfo = 0;
|
|
}
|
|
else
|
|
if (bType == bTypeTopicCounted)
|
|
{
|
|
lcbRet = LcbMapSDFF(isdff, SE_MOBJTOPICCOUNTED, (QV)qmobj, qvSrc);
|
|
}
|
|
else
|
|
if (bType > MAX_UNCOUNTED_OBJ_TYPE)
|
|
{
|
|
lcbRet = LcbMapSDFF(isdff, SE_MOBJNORMCOUNTED, (QV)qmobj, qvSrc);
|
|
}
|
|
else
|
|
{
|
|
lcbRet = LcbMapSDFF(isdff, SE_MOBJNORMUNCOUNTED, (QV)qmobj, qvSrc);
|
|
qmobj->wObjInfo = 0;
|
|
}
|
|
|
|
return (int)lcbRet;
|
|
#endif
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
| CbUnpackMTOP(qmtop, qv, wHelpVer) |
|
|
| |
|
|
| Purpose: Unpacks an MTOP data structure. |
|
|
-------------------------------------------------------------------------*/
|
|
#ifdef _X86_
|
|
int STDCALL CbUnpackMTOP(QMTOP qmtop, void* qv, WORD wHelpVer, VA vaTopic,
|
|
DWORD lcbTopic, VA vaPostTopicFC, DWORD lcbTopicFC)
|
|
{
|
|
void* qvFirst = qv;
|
|
|
|
if (wHelpVer == wVersion3_0) {
|
|
/*
|
|
* In Help 3.0, FCLs were INT16's cast to signed longs. Scary! This
|
|
* is important because itoNil was (WORD) -1, not (LONG) -1.
|
|
*/
|
|
|
|
qmtop->prev.ito = * ((QI) qv);
|
|
qv = ((QL) qv) + 1;
|
|
qmtop->next.ito = * ((QI) qv);
|
|
qv = ((QL) qv) + 1;
|
|
ASSERT( itoNil == -1L); /* If this changes, we need to add some code *
|
|
* here to translate */
|
|
qmtop->lTopicNo = -1; /* REVIEW: We really need a topic number type */
|
|
|
|
// Must manufacture the new 3.5 VA fields:
|
|
// If the topic FC is the last FC in a block, and there is padding
|
|
// between it and the end of the block, vaTopic + lcbTopic
|
|
// will be #paddingbytes too small, but the scrollbar code should
|
|
// handle this.
|
|
//
|
|
// In the case that there is no next sequential topic, we manufacture
|
|
// an address by adding the length of the topic FC to the VA of the
|
|
// topic FC.
|
|
|
|
OffsetToVA30( &(qmtop->vaNextSeqTopic), VAToOffset30(&vaTopic) + lcbTopic);
|
|
qmtop->vaNSR.dword = vaNil;
|
|
if (vaPostTopicFC.dword != vaNil)
|
|
qmtop->vaSR = vaPostTopicFC;
|
|
else
|
|
OffsetToVA30( &(qmtop->vaSR), VAToOffset30(&vaTopic) + lcbTopicFC);
|
|
|
|
return(((PBYTE)qv - (PBYTE)qvFirst));
|
|
}
|
|
|
|
// No Packing with 3.5 -- just copy it whole-hog:
|
|
*qmtop = *(QMTOP)qv;
|
|
return(sizeof(MTOP));
|
|
#else
|
|
INT PASCAL CbUnpackMTOP(QMTOP qmtop, QV qvSrc, WORD wHelpVer, VA vaTopic,
|
|
ULONG lcbTopic, VA vaPostTopicFC, ULONG lcbTopicFC, int isdff)
|
|
{
|
|
|
|
if (wHelpVer == wVersion3_0)
|
|
{
|
|
QV qvFirst = qvSrc;
|
|
WORD wIto;
|
|
|
|
/* In Help 3.0, FCLs were int's cast to signed longs. Scary!
|
|
* This is important because itoNil was (WORD) -1, not (LONG) -1.
|
|
*/
|
|
/* maha 3.5 browse fix */
|
|
/* Warning: Casting a WORD to ITO i.e to a long doesn't sign extend */
|
|
wIto = WQuickMapSDFF(isdff, TE_WORD, qvSrc);
|
|
if ( wIto == (WORD)-1 )
|
|
qmtop->prev.ito = -1L ;
|
|
else qmtop->prev.ito = (ITO)wIto;
|
|
qmtop->prev.ito = (ITO)LQuickMapSDFF(isdff, TE_LONG, &(qmtop->prev.ito));
|
|
/* Put it back in disk format as a long */
|
|
(QB)qvSrc += LcbStructSizeSDFF(isdff, TE_LONG);
|
|
wIto = WQuickMapSDFF(isdff, TE_WORD, qvSrc);
|
|
if ( wIto == (WORD)-1 )
|
|
qmtop->next.ito = -1L ;
|
|
else qmtop->next.ito = (ITO)wIto;
|
|
/* Put it back in disk format as a long */
|
|
qmtop->next.ito = (ITO)LQuickMapSDFF(isdff, TE_LONG, &(qmtop->next.ito));
|
|
(QB)qvSrc += LcbStructSizeSDFF(isdff, TE_LONG);
|
|
|
|
AssertF( itoNil == -1L); /* If this changes, we need to add some code *
|
|
* here to translate */
|
|
qmtop->lTopicNo = -1; /* REVIEW: We really need a topic number type */
|
|
|
|
/* Must manufacture the new 3.5 VA fields: */
|
|
/* If the topic FC is the last FC in a block, and there is padding */
|
|
/* between it and the end of the block, vaTopic + lcbTopic */
|
|
/* will be #paddingbytes too small, but the scrollbar code should */
|
|
/* handle this. */
|
|
|
|
/* In the case that there is no next sequential topic, we manufacture */
|
|
/* an address by adding the length of the topic FC to the VA of the */
|
|
/* topic FC. */
|
|
|
|
OffsetToVA30( &(qmtop->vaNextSeqTopic), VAToOffset30(&vaTopic) + lcbTopic);
|
|
qmtop->vaNSR.dword = vaNil;
|
|
if (vaPostTopicFC.dword != vaNil)
|
|
qmtop->vaSR = vaPostTopicFC;
|
|
else
|
|
OffsetToVA30( &(qmtop->vaSR), VAToOffset30(&vaTopic) + lcbTopicFC);
|
|
|
|
return((INT) ((QB)qvSrc - (QB)qvFirst));
|
|
}
|
|
|
|
return((INT)LcbMapSDFF(isdff, SE_MTOP, (QV)qmtop, qvSrc));
|
|
#endif // _X86_
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
static int STDCALL FVerifyQMOPG(QMOPG qmopg)
|
|
{
|
|
/*----------------------------------------------------------------------------*\
|
|
* Reference to quiet the compiler
|
|
\*----------------------------------------------------------------------------*/
|
|
qmopg;
|
|
|
|
#ifdef MAGIC
|
|
Assert(qmopg->bMagic == bMagicMOPG);
|
|
#endif
|
|
ASSERT(qmopg->libText >= 0);
|
|
ASSERT(!qmopg->fStyle);
|
|
ASSERT(!qmopg->fMoreFlags);
|
|
ASSERT(qmopg->wJustify >= 0 && qmopg->wJustify <= wJustifyMost);
|
|
ASSERT(qmopg->ySpaceOver >= 0);
|
|
ASSERT(qmopg->ySpaceUnder >= 0);
|
|
ASSERT(qmopg->yLineSpacing >= -10000 && qmopg->yLineSpacing < 10000);
|
|
ASSERT(qmopg->xRightIndent >= 0);
|
|
ASSERT(qmopg->xFirstIndent >= -10000 && qmopg->xFirstIndent < 10000);
|
|
ASSERT(qmopg->xTabSpacing >= 0 && qmopg->xTabSpacing < 10000);
|
|
ASSERT(qmopg->cTabs >= 0 && qmopg->cTabs <= cxTabsMax);
|
|
return(TRUE);
|
|
}
|
|
|
|
#endif
|