Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * hdrftrlist.c
 * Copyright (C) 2004,2005 A.J. van Os; Released under GNU GPL
 *
 * Description:
 * Build, read and destroy list(s) of Word Header/footer information
 */

#include <string.h>
#include "antiword.h"


#define HDR_EVEN_PAGES  0
#define HDR_ODD_PAGES   1
#define FTR_EVEN_PAGES  2
#define FTR_ODD_PAGES   3
#define HDR_FIRST_PAGE  4
#define FTR_FIRST_PAGE  5

/*
 * Private structures to hide the way the information
 * is stored from the rest of the program
 */
typedef struct hdrftr_local_tag {
        hdrftr_block_type       tInfo;
        ULONG                   ulCharPosStart;
        ULONG                   ulCharPosNext;
        BOOL                    bUseful;
        BOOL                    bTextOriginal;
} hdrftr_local_type;
typedef struct hdrftr_mem_tag {
        hdrftr_local_type       atElement[6];
} hdrftr_mem_type;

/* Variables needed to write the Header/footer Information List */
static hdrftr_mem_type  *pHdrFtrList = NULL;
static size_t           tHdrFtrLen = 0;


/*
 * vDestroyHdrFtrInfoList - destroy the Header/footer Information List
 */
void
vDestroyHdrFtrInfoList(void)
{
        hdrftr_mem_type *pRecord;
        output_type     *pCurr, *pNext;
        size_t          tHdrFtr, tIndex;

        DBG_MSG("vDestroyHdrFtrInfoList");

        /* Free the Header/footer Information List */
        for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
                pRecord = pHdrFtrList + tHdrFtr;
                for (tIndex = 0;
                     tIndex < elementsof(pRecord->atElement);
                     tIndex++) {
                        if (!pRecord->atElement[tIndex].bTextOriginal) {
                                continue;
                        }
                        pCurr = pRecord->atElement[tIndex].tInfo.pText;
                        while (pCurr != NULL) {
                                pCurr->szStorage = xfree(pCurr->szStorage);
                                pNext = pCurr->pNext;
                                pCurr = xfree(pCurr);
                                pCurr = pNext;
                        }
                }
        }
        pHdrFtrList = xfree(pHdrFtrList);
        /* Reset all control variables */
        tHdrFtrLen = 0;
} /* end of vDestroyHdrFtrInfoList */

/*
 * vCreat8HdrFtrInfoList - Create the Header/footer Information List
 */
void
vCreat8HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
{
        hdrftr_mem_type *pListMember;
        size_t  tHdrFtr, tIndex, tMainIndex;

        fail(aulCharPos == NULL);

        DBG_DEC(tLength);
        if (tLength <= 1) {
                return;
        }
        tHdrFtrLen = tLength / 12;
        if (tLength % 12 != 0 && tLength % 12 != 1) {
                tHdrFtrLen++;
        }
        DBG_DEC(tHdrFtrLen);

        pHdrFtrList = xcalloc(tHdrFtrLen, sizeof(hdrftr_mem_type));

        for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
                pListMember = pHdrFtrList + tHdrFtr;
                for (tIndex = 0, tMainIndex = tHdrFtr * 12;
                     tIndex < 6 && tMainIndex < tLength;
                     tIndex++, tMainIndex++) {
                        pListMember->atElement[tIndex].tInfo.pText = NULL;
                        pListMember->atElement[tIndex].ulCharPosStart =
                                                aulCharPos[tMainIndex];
                        if (tMainIndex + 1 < tLength) {
                                pListMember->atElement[tIndex].ulCharPosNext =
                                        aulCharPos[tMainIndex + 1];
                        } else {
                                pListMember->atElement[tIndex].ulCharPosNext =
                                        aulCharPos[tMainIndex];
                        }
                }
        }
} /* end of vCreat8HdrFtrInfoList */

/*
 * vCreat6HdrFtrInfoList - Create the Header/footer Information List
 */
void
vCreat6HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
{
        static const size_t     atIndex[] =
                { SIZE_T_MAX, SIZE_T_MAX, FTR_FIRST_PAGE, HDR_FIRST_PAGE,
                  FTR_ODD_PAGES, FTR_EVEN_PAGES, HDR_ODD_PAGES, HDR_EVEN_PAGES,
                };
        hdrftr_mem_type *pListMember;
        size_t  tHdrFtr, tTmp, tIndex, tMainIndex, tBit;
        UCHAR   ucDopSpecification, ucSepSpecification;

        fail(aulCharPos == NULL);

        DBG_DEC(tLength);
        if (tLength <= 1) {
                return;
        }
        tHdrFtrLen = tGetNumberOfSections();
        if (tHdrFtrLen == 0) {
                tHdrFtrLen = 1;
        }
        DBG_DEC(tHdrFtrLen);

        pHdrFtrList = xcalloc(tHdrFtrLen, sizeof(hdrftr_mem_type));

        /* Get the start index in aulCharPos */
        ucDopSpecification = ucGetDopHdrFtrSpecification();
        DBG_HEX(ucDopSpecification & 0xe0);
        tMainIndex = 0;
        for (tBit = 7; tBit >= 5; tBit--) {
                if ((ucDopSpecification & BIT(tBit)) != 0) {
                        tMainIndex++;
                }
        }
        DBG_DEC(tMainIndex);

        for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
                ucSepSpecification = ucGetSepHdrFtrSpecification(tHdrFtr);
                DBG_HEX(ucSepSpecification & 0xfc);
                pListMember = pHdrFtrList + tHdrFtr;
                for (tTmp = 0;
                     tTmp < elementsof(pListMember->atElement);
                     tTmp++) {
                        pListMember->atElement[tTmp].tInfo.pText = NULL;
                }
                for (tBit = 7; tBit >= 2; tBit--) {
                        if (tMainIndex >= tLength) {
                                break;
                        }
                        if ((ucSepSpecification & BIT(tBit)) == 0) {
                                continue;
                        }
                        tIndex = atIndex[tBit];
                        fail(tIndex >= 6);
                        pListMember->atElement[tIndex].ulCharPosStart =
                                aulCharPos[tMainIndex];
                        if (tMainIndex + 1 < tLength) {
                                pListMember->atElement[tIndex].ulCharPosNext =
                                        aulCharPos[tMainIndex + 1];
                        } else {
                                pListMember->atElement[tIndex].ulCharPosNext =
                                        aulCharPos[tMainIndex];
                        }
                        tMainIndex++;
                }
        }
} /* end of vCreat6HdrFtrInfoList */

/*
 * vCreat2HdrFtrInfoList - Create the Header/footer Information List
 */
void
vCreat2HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
{
        vCreat6HdrFtrInfoList(aulCharPos, tLength);
} /* end of vCreat2HdrFtrInfoList */

/*
 * pGetHdrFtrInfo - get the Header/footer information
 */
const hdrftr_block_type *
pGetHdrFtrInfo(int iSectionIndex,
        BOOL bWantHeader, BOOL bOddPage, BOOL bFirstInSection)
{
        hdrftr_mem_type *pCurr;

        fail(iSectionIndex < 0);
        fail(pHdrFtrList == NULL && tHdrFtrLen != 0);

        if (pHdrFtrList == NULL || tHdrFtrLen == 0) {
                /* No information */
                return NULL;
        }

        if (iSectionIndex < 0) {
                iSectionIndex = 0;
        } else if (iSectionIndex >= (int)tHdrFtrLen) {
                iSectionIndex = (int)(tHdrFtrLen - 1);
        }

        pCurr = pHdrFtrList + iSectionIndex;

        if (bFirstInSection) {
                if (bWantHeader) {
                        return &pCurr->atElement[HDR_FIRST_PAGE].tInfo;
                } else {
                        return &pCurr->atElement[FTR_FIRST_PAGE].tInfo;
                }
        } else {
                if (bWantHeader) {
                        if (bOddPage) {
                                return &pCurr->atElement[HDR_ODD_PAGES].tInfo;
                        } else {
                                return &pCurr->atElement[HDR_EVEN_PAGES].tInfo;
                        }
                } else {
                        if (bOddPage) {
                                return &pCurr->atElement[FTR_ODD_PAGES].tInfo;
                        } else {
                                return &pCurr->atElement[FTR_EVEN_PAGES].tInfo;
                        }
                }
        }
} /* end of pGetHdrFtrInfo */

/*
 * lComputeHdrFtrHeight - compute the height of a header or footer
 *
 * Returns the height in DrawUnits
 */
static long
lComputeHdrFtrHeight(const output_type *pAnchor)
{
        const output_type *pCurr;
        long    lTotal;
        USHORT  usFontSizeMax;

        lTotal = 0;
        usFontSizeMax = 0;
        for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
                if (pCurr->tNextFree == 1) {
                        if (pCurr->szStorage[0] == PAR_END) {
                                /* End of a paragraph */
                                lTotal += lComputeLeading(usFontSizeMax);
                                lTotal += lMilliPoints2DrawUnits(
                                                (long)pCurr->usFontSize * 200);
                                usFontSizeMax = 0;
                                continue;
                        }
                        if (pCurr->szStorage[0] == HARD_RETURN) {
                                /* End of a line */
                                lTotal += lComputeLeading(usFontSizeMax);
                                usFontSizeMax = 0;
                                continue;
                        }
                }
                if (pCurr->usFontSize > usFontSizeMax) {
                        usFontSizeMax = pCurr->usFontSize;
                }
        }
        if (usFontSizeMax != 0) {
                /* Height of the last paragraph */
                lTotal += lComputeLeading(usFontSizeMax);
        }
        return lTotal;
} /* end of lComputeHdrFtrHeight */

/*
 * vPrepareHdrFtrText - prepare the header/footer text
 */
void
vPrepareHdrFtrText(FILE *pFile)
{
        hdrftr_mem_type         *pCurr, *pPrev;
        hdrftr_local_type       *pTmp;
        output_type             *pText;
        size_t          tHdrFtr, tIndex;

        fail(pFile == NULL);
        fail(pHdrFtrList == NULL && tHdrFtrLen != 0);

        if (pHdrFtrList == NULL || tHdrFtrLen == 0) {
                /* No information */
                return;
        }

        /* Fill text, text height and useful-ness */
        for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
                pCurr = pHdrFtrList + tHdrFtr;
                for (tIndex = 0;
                     tIndex < elementsof(pHdrFtrList->atElement);
                     tIndex++) {
                        pTmp = &pCurr->atElement[tIndex];
                        pTmp->bUseful =
                                pTmp->ulCharPosStart != pTmp->ulCharPosNext;
                        if (pTmp->bUseful) {
                                pText = pHdrFtrDecryptor(pFile,
                                                pTmp->ulCharPosStart,
                                                pTmp->ulCharPosNext);
                                pTmp->tInfo.pText = pText;
                                pTmp->tInfo.lHeight =
                                                lComputeHdrFtrHeight(pText);
                                pTmp->bTextOriginal = pText != NULL;
                        } else {
                                pTmp->tInfo.pText = NULL;
                                pTmp->tInfo.lHeight = 0;
                                pTmp->bTextOriginal = FALSE;
                        }
                }
        }

        /* Replace not-useful records by using inheritance */
        if (pHdrFtrList->atElement[HDR_FIRST_PAGE].bUseful) {
                pTmp = &pHdrFtrList->atElement[HDR_ODD_PAGES];
                if (!pTmp->bUseful) {
                        *pTmp = pHdrFtrList->atElement[HDR_FIRST_PAGE];
                        pTmp->bTextOriginal = FALSE;
                }
                pTmp = &pHdrFtrList->atElement[HDR_EVEN_PAGES];
                if (!pTmp->bUseful) {
                        *pTmp = pHdrFtrList->atElement[HDR_FIRST_PAGE];
                        pTmp->bTextOriginal = FALSE;
                }
        }
        if (pHdrFtrList->atElement[FTR_FIRST_PAGE].bUseful) {
                pTmp = &pHdrFtrList->atElement[FTR_ODD_PAGES];
                if (!pTmp->bUseful) {
                        *pTmp = pHdrFtrList->atElement[FTR_FIRST_PAGE];
                        pTmp->bTextOriginal = FALSE;
                }
                pTmp = &pHdrFtrList->atElement[FTR_EVEN_PAGES];
                if (!pTmp->bUseful) {
                        *pTmp = pHdrFtrList->atElement[FTR_FIRST_PAGE];
                        pTmp->bTextOriginal = FALSE;
                }
        }
        for (tHdrFtr = 1, pCurr = &pHdrFtrList[1];
             tHdrFtr < tHdrFtrLen;
             tHdrFtr++, pCurr++) {
                pPrev = pCurr - 1;
                for (tIndex = 0;
                     tIndex < elementsof(pHdrFtrList->atElement);
                     tIndex++) {
                        if (!pCurr->atElement[tIndex].bUseful &&
                            pPrev->atElement[tIndex].bUseful) {
                                pCurr->atElement[tIndex] =
                                                pPrev->atElement[tIndex];
                                pCurr->atElement[tIndex].bTextOriginal = FALSE;
                        }
                }
        }
} /* end of vPrepareHdrFtrText */