Subversion Repositories planix.SVN

Rev

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

/*
 * notes.c
 * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
 *
 * Description:
 * Functions to tell the difference between footnotes and endnotes
 */

#include "antiword.h"

/*
 * Private structures to hide the way the information
 * is stored from the rest of the program
 */
typedef struct footnote_local_tag {
        footnote_block_type     tInfo;
        ULONG                   ulCharPosStart;
        ULONG                   ulCharPosNext;
        BOOL                    bUseful;
} footnote_local_type;

/* Variables needed to write the Footnote and Endnote information */
static ULONG    *aulFootnoteList = NULL;
static size_t   tFootnoteListLength = 0;
static ULONG    *aulEndnoteList = NULL;
static size_t   tEndnoteListLength = 0;
/* Variables needed to write the Footnote Text */
static footnote_local_type      *pFootnoteText = NULL;
static size_t                   tFootnoteTextLength = 0;


/*
 * Destroy the lists with footnote and endnote information
 */
void
vDestroyNotesInfoLists(void)
{
        footnote_local_type     *pRecord;
        size_t                  tFootnote;

        TRACE_MSG("vDestroyNotesInfoLists");

        /* Free the lists and reset all control variables */
        aulEndnoteList = xfree(aulEndnoteList);
        aulFootnoteList = xfree(aulFootnoteList);
        tEndnoteListLength = 0;
        tFootnoteListLength = 0;
        for (tFootnote = 0; tFootnote < tFootnoteTextLength; tFootnote++) {
                pRecord = pFootnoteText + tFootnote;
                pRecord->tInfo.szText = xfree(pRecord->tInfo.szText);
        }
        pFootnoteText = xfree(pFootnoteText);
        tFootnoteTextLength = 0;
} /* end of vDestroyNotesInfoLists */

/*
 * Build the list with footnote information for Word for DOS files
 */
static void
vGet0FootnotesInfoAndText(FILE *pFile, const UCHAR *aucHeader)
{
        footnote_local_type     *pCurr;
        UCHAR   *aucBuffer;
        ULONG   ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
        ULONG   ulCharPos, ulBeginNextBlock;
        size_t  tFootnotes, tFootnoteInfoLen;
        size_t  tIndex;
        UCHAR   aucTmp[2];

        TRACE_MSG("vGet0FootnotesInfoAndText");

        fail(pFile == NULL || aucHeader == NULL);

        ulBeginOfText = 128;
        NO_DBG_HEX(ulBeginOfText);
        ulBeginFootnoteInfo =  128 * (ULONG)usGetWord(0x14, aucHeader);
        DBG_HEX(ulBeginFootnoteInfo);
        ulBeginNextBlock = 128 * (ULONG)usGetWord(0x16, aucHeader);
        DBG_HEX(ulBeginNextBlock);

        if (ulBeginFootnoteInfo == ulBeginNextBlock) {
                DBG_MSG("No Footnotes in this document");
                return;
        }

        /* Read the the number of footnotes + 1 */
        if (!bReadBytes(aucTmp, 2, ulBeginFootnoteInfo, pFile)) {
                return;
        }
        tFootnotes = (size_t)usGetWord(0, aucTmp);
        if (tFootnotes < 2) {
                DBG_MSG("No Footnotes in this document (2)");
        }
        DBG_DEC(tFootnotes);
        tFootnoteInfoLen =  8 * tFootnotes;

        aucBuffer = xmalloc(tFootnoteInfoLen);
        if (!bReadBytes(aucBuffer,
                        tFootnoteInfoLen, ulBeginFootnoteInfo + 4, pFile)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);

        /* Get footnote information */
        fail(tFootnoteListLength != 0);
        tFootnoteListLength = tFootnotes - 1;
        fail(tFootnoteListLength == 0);

        fail(aulFootnoteList != NULL);
        aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));

        for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
                ulOffset = ulGetLong(tIndex * 8, aucBuffer);
                DBG_HEX(ulOffset);
                ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
                DBG_HEX(ulFileOffset);
                aulFootnoteList[tIndex] = ulFileOffset;
        }

        /* Get footnote text */
        fail(tFootnoteTextLength != 0);
        tFootnoteTextLength = tFootnotes - 1;
        fail(tFootnoteTextLength == 0);

        fail(pFootnoteText != NULL);
        pFootnoteText = xcalloc(tFootnoteTextLength,
                                sizeof(footnote_local_type));

        for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
                pCurr = pFootnoteText + tIndex;
                pCurr->tInfo.szText = NULL;
                ulOffset = ulGetLong(tIndex * 8 + 4, aucBuffer);
                DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfText + ulOffset;
                DBG_HEX(ulCharPos);
                DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosStart = ulCharPos;
                ulOffset = ulGetLong((tIndex + 1) * 8 + 4, aucBuffer);
                DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfText + ulOffset;
                DBG_HEX(ulCharPos);
                DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosNext = ulCharPos;
                pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet0FootnotesInfoAndText */

/*
 * Build the lists note information for Word for DOS files
 */
static void
vGet0NotesInfo(FILE *pFile, const UCHAR *aucHeader)
{
        TRACE_MSG("vGet0NotesInfo");

        vGet0FootnotesInfoAndText(pFile, aucHeader);
        /* There are no endnotes in a Word for DOS file */
} /* end of vGet0NotesInfo */

/*
 * Build the list with footnote information for WinWord 1/2 files
 */
static void
vGet2FootnotesInfo(FILE *pFile, const UCHAR *aucHeader)
{
        UCHAR   *aucBuffer;
        ULONG   ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
        size_t  tFootnoteInfoLen;
        size_t  tIndex;

        TRACE_MSG("vGet2FootnotesInfo");

        fail(pFile == NULL || aucHeader == NULL);

        ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
        NO_DBG_HEX(ulBeginOfText);
        ulBeginFootnoteInfo = ulGetLong(0x64, aucHeader); /* fcPlcffndRef */
        NO_DBG_HEX(ulBeginFootnoteInfo);
        tFootnoteInfoLen = (size_t)usGetWord(0x68, aucHeader); /* cbPlcffndRef */
        NO_DBG_DEC(tFootnoteInfoLen);

        if (tFootnoteInfoLen < 10) {
                DBG_MSG("No Footnotes in this document");
                return;
        }

        aucBuffer = xmalloc(tFootnoteInfoLen);
        if (!bReadBytes(aucBuffer,
                        tFootnoteInfoLen, ulBeginFootnoteInfo, pFile)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);

        fail(tFootnoteListLength != 0);
        tFootnoteListLength = (tFootnoteInfoLen - 4) / 6;
        fail(tFootnoteListLength == 0);

        fail(aulFootnoteList != NULL);
        aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));

        for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
                NO_DBG_HEX(ulFileOffset);
                aulFootnoteList[tIndex] = ulFileOffset;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet2FootnotesInfo */

/*
 * Build the list with footnote text information for WinWord 1/2 files
 */
static void
vGet2FootnotesText(FILE *pFile, const UCHAR *aucHeader)
{
        footnote_local_type     *pCurr;
        UCHAR   *aucBuffer;
        ULONG   ulCharPos, ulBeginOfFootnotes, ulOffset, ulBeginFootnoteText;
        size_t  tFootnoteTextLen;
        size_t  tIndex;

        TRACE_MSG("vGet2FootnotesText");

        fail(pFile == NULL || aucHeader == NULL);

        ulBeginOfFootnotes = ulGetLong(0x18, aucHeader); /* fcMin */
        ulBeginOfFootnotes += ulGetLong(0x34, aucHeader); /* ccpText */
        NO_DBG_HEX(ulBeginOfFootnotes);

        ulBeginFootnoteText = ulGetLong(0x6a, aucHeader); /* fcPlcffndTxt */
        NO_DBG_HEX(ulBeginFootnoteText);
        tFootnoteTextLen =
                (size_t)usGetWord(0x6e, aucHeader); /* cbPlcffndTxt */
        NO_DBG_DEC(tFootnoteTextLen);

        if (tFootnoteTextLen < 12) {
                DBG_MSG("No Footnote text in this document");
                return;
        }

        aucBuffer = xmalloc(tFootnoteTextLen);
        if (!bReadBytes(aucBuffer,
                        tFootnoteTextLen, ulBeginFootnoteText, pFile)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteTextLen);

        fail(tFootnoteTextLength != 0);
        tFootnoteTextLength = tFootnoteTextLen / 4 - 2;
        fail(tFootnoteTextLength == 0);

        fail(pFootnoteText != NULL);
        pFootnoteText = xcalloc(tFootnoteTextLength,
                                sizeof(footnote_local_type));

        for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
                pCurr = pFootnoteText + tIndex;
                pCurr->tInfo.szText = NULL;
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfFootnotes + ulOffset;
                NO_DBG_HEX(ulCharPos);
                NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosStart = ulCharPos;
                ulOffset = ulGetLong(tIndex * 4 + 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfFootnotes + ulOffset;
                NO_DBG_HEX(ulCharPos);
                NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosNext = ulCharPos;
                pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet2FootnotesText */

/*
 * Build the lists note information for WinWord 1/2 files
 */
static void
vGet2NotesInfo(FILE *pFile, const UCHAR *aucHeader)
{
        TRACE_MSG("vGet2NotesInfo");

        vGet2FootnotesInfo(pFile, aucHeader);
        vGet2FootnotesText(pFile, aucHeader);
        /* There are no endnotes in a WinWord 1/2 file */
} /* end of vGet2NotesInfo */

/*
 * Build the list with footnote information for Word 6/7 files
 */
static void
vGet6FootnotesInfo(FILE *pFile, ULONG ulStartBlock,
        const ULONG *aulBBD, size_t tBBDLen,
        const UCHAR *aucHeader)
{
        UCHAR   *aucBuffer;
        ULONG   ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
        size_t  tFootnoteInfoLen;
        size_t  tIndex;

        TRACE_MSG("vGet6FootnotesInfo");

        fail(pFile == NULL || aucHeader == NULL);
        fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
        fail(aulBBD == NULL);

        ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
        NO_DBG_HEX(ulBeginOfText);
        ulBeginFootnoteInfo = ulGetLong(0x68, aucHeader); /* fcPlcffndRef */
        NO_DBG_HEX(ulBeginFootnoteInfo);
        tFootnoteInfoLen =
                (size_t)ulGetLong(0x6c, aucHeader); /* lcbPlcffndRef */
        NO_DBG_DEC(tFootnoteInfoLen);

        if (tFootnoteInfoLen < 10) {
                DBG_MSG("No Footnotes in this document");
                return;
        }

        aucBuffer = xmalloc(tFootnoteInfoLen);
        if (!bReadBuffer(pFile, ulStartBlock,
                        aulBBD, tBBDLen, BIG_BLOCK_SIZE,
                        aucBuffer, ulBeginFootnoteInfo, tFootnoteInfoLen)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);

        fail(tFootnoteListLength != 0);
        tFootnoteListLength = (tFootnoteInfoLen - 4) / 6;
        fail(tFootnoteListLength == 0);

        fail(aulFootnoteList != NULL);
        aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));

        for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
                NO_DBG_HEX(ulFileOffset);
                aulFootnoteList[tIndex] = ulFileOffset;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet6FootnotesInfo */

/*
 * Build the list with footnote text information for Word 6/7 files
 */
static void
vGet6FootnotesText(FILE *pFile, ULONG ulStartBlock,
        const ULONG *aulBBD, size_t tBBDLen,
        const UCHAR *aucHeader)
{
        footnote_local_type     *pCurr;
        UCHAR   *aucBuffer;
        ULONG   ulCharPos, ulBeginOfFootnotes, ulOffset, ulBeginFootnoteText;
        size_t  tFootnoteTextLen;
        size_t  tIndex;

        TRACE_MSG("vGet6FootnotesText");

        fail(pFile == NULL || aucHeader == NULL);
        fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
        fail(aulBBD == NULL);

        ulBeginOfFootnotes = ulGetLong(0x18, aucHeader); /* fcMin */
        ulBeginOfFootnotes += ulGetLong(0x34, aucHeader); /* ccpText */
        NO_DBG_HEX(ulBeginOfFootnotes);

        ulBeginFootnoteText = ulGetLong(0x70, aucHeader); /* fcPlcffndTxt */
        NO_DBG_HEX(ulBeginFootnoteText);
        tFootnoteTextLen =
                (size_t)ulGetLong(0x74, aucHeader); /* lcbPlcffndTxt */
        NO_DBG_DEC(tFootnoteTextLen);

        if (tFootnoteTextLen < 12) {
                DBG_MSG("No Footnote text in this document");
                return;
        }

        aucBuffer = xmalloc(tFootnoteTextLen);
        if (!bReadBuffer(pFile, ulStartBlock,
                        aulBBD, tBBDLen, BIG_BLOCK_SIZE,
                        aucBuffer, ulBeginFootnoteText, tFootnoteTextLen)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteTextLen);

        fail(tFootnoteTextLength != 0);
        tFootnoteTextLength = tFootnoteTextLen / 4 - 2;
        fail(tFootnoteTextLength == 0);

        fail(pFootnoteText != NULL);
        pFootnoteText = xcalloc(tFootnoteTextLength,
                                sizeof(footnote_local_type));

        for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
                pCurr = pFootnoteText + tIndex;
                pCurr->tInfo.szText = NULL;
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfFootnotes + ulOffset;
                NO_DBG_HEX(ulCharPos);
                NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosStart = ulCharPos;
                ulOffset = ulGetLong(tIndex * 4 + 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfFootnotes + ulOffset;
                NO_DBG_HEX(ulCharPos);
                NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosNext = ulCharPos;
                pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet6FootnotesText */

/*
 * Build the list with endnote information for Word 6/7 files
 */
static void
vGet6EndnotesInfo(FILE *pFile, ULONG ulStartBlock,
        const ULONG *aulBBD, size_t tBBDLen,
        const UCHAR *aucHeader)
{
        UCHAR   *aucBuffer;
        ULONG   ulFileOffset, ulBeginOfText, ulOffset, ulBeginEndnoteInfo;
        size_t  tEndnoteInfoLen;
        size_t  tIndex;

        TRACE_MSG("vGet6EndnotesInfo");

        fail(pFile == NULL || aucHeader == NULL);
        fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
        fail(aulBBD == NULL);

        ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
        NO_DBG_HEX(ulBeginOfText);
        ulBeginEndnoteInfo = ulGetLong(0x1d2, aucHeader); /* fcPlcfendRef */
        NO_DBG_HEX(ulBeginEndnoteInfo);
        tEndnoteInfoLen =
                (size_t)ulGetLong(0x1d6, aucHeader); /* lcbPlcfendRef */
        NO_DBG_DEC(tEndnoteInfoLen);

        if (tEndnoteInfoLen < 10) {
                DBG_MSG("No Endnotes in this document");
                return;
        }

        aucBuffer = xmalloc(tEndnoteInfoLen);
        if (!bReadBuffer(pFile, ulStartBlock,
                        aulBBD, tBBDLen, BIG_BLOCK_SIZE,
                        aucBuffer, ulBeginEndnoteInfo, tEndnoteInfoLen)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tEndnoteInfoLen);

        fail(tEndnoteListLength != 0);
        tEndnoteListLength = (tEndnoteInfoLen - 4) / 6;
        fail(tEndnoteListLength == 0);

        fail(aulEndnoteList != NULL);
        aulEndnoteList = xcalloc(tEndnoteListLength, sizeof(ULONG));

        for (tIndex = 0; tIndex < tEndnoteListLength; tIndex++) {
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
                NO_DBG_HEX(ulFileOffset);
                aulEndnoteList[tIndex] = ulFileOffset;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet6EndnotesInfo */

/*
 * Build the lists note information for Word 6/7 files
 */
static void
vGet6NotesInfo(FILE *pFile, ULONG ulStartBlock,
        const ULONG *aulBBD, size_t tBBDLen,
        const UCHAR *aucHeader)
{
        TRACE_MSG("vGet6NotesInfo");

        vGet6FootnotesInfo(pFile, ulStartBlock,
                        aulBBD, tBBDLen, aucHeader);
        vGet6FootnotesText(pFile, ulStartBlock,
                        aulBBD, tBBDLen, aucHeader);
        vGet6EndnotesInfo(pFile, ulStartBlock,
                        aulBBD, tBBDLen, aucHeader);
} /* end of vGet6NotesInfo */

/*
 * Build the list with footnote information for Word 8/9/10 files
 */
static void
vGet8FootnotesInfo(FILE *pFile, const pps_info_type *pPPS,
        const ULONG *aulBBD, size_t tBBDLen,
        const ULONG *aulSBD, size_t tSBDLen,
        const UCHAR *aucHeader)
{
        const ULONG     *aulBlockDepot;
        UCHAR   *aucBuffer;
        ULONG   ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
        size_t  tFootnoteInfoLen, tBlockDepotLen, tBlockSize;
        size_t  tIndex;

        TRACE_MSG("vGet8FootnotesInfo");

        ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
        NO_DBG_HEX(ulBeginOfText);
        ulBeginFootnoteInfo = ulGetLong(0xaa, aucHeader); /* fcPlcffndRef */
        NO_DBG_HEX(ulBeginFootnoteInfo);
        tFootnoteInfoLen =
                (size_t)ulGetLong(0xae, aucHeader); /* lcbPlcffndRef */
        NO_DBG_DEC(tFootnoteInfoLen);

        if (tFootnoteInfoLen < 10) {
                DBG_MSG("No Footnotes in this document");
                return;
        }

        NO_DBG_DEC(pPPS->tTable.ulSB);
        NO_DBG_HEX(pPPS->tTable.ulSize);
        if (pPPS->tTable.ulSize == 0) {
                DBG_MSG("No footnotes information");
                return;
        }

        if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
                /* Use the Small Block Depot */
                aulBlockDepot = aulSBD;
                tBlockDepotLen = tSBDLen;
                tBlockSize = SMALL_BLOCK_SIZE;
        } else {
                /* Use the Big Block Depot */
                aulBlockDepot = aulBBD;
                tBlockDepotLen = tBBDLen;
                tBlockSize = BIG_BLOCK_SIZE;
        }
        aucBuffer = xmalloc(tFootnoteInfoLen);
        if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
                        aulBlockDepot, tBlockDepotLen, tBlockSize,
                        aucBuffer, ulBeginFootnoteInfo, tFootnoteInfoLen)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);

        fail(tFootnoteListLength != 0);
        tFootnoteListLength = (tFootnoteInfoLen - 4) / 6;
        fail(tFootnoteListLength == 0);

        fail(aulFootnoteList != NULL);
        aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));

        for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
                NO_DBG_HEX(ulFileOffset);
                aulFootnoteList[tIndex] = ulFileOffset;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet8FootnotesInfo */

/*
 * Build the list with footnote text information for Word 8/9/10 files
 */
static void
vGet8FootnotesText(FILE *pFile, const pps_info_type *pPPS,
        const ULONG *aulBBD, size_t tBBDLen,
        const ULONG *aulSBD, size_t tSBDLen,
        const UCHAR *aucHeader)
{
        footnote_local_type     *pCurr;
        const ULONG     *aulBlockDepot;
        UCHAR   *aucBuffer;
        ULONG   ulCharPos, ulBeginOfFootnotes, ulOffset, ulBeginFootnoteText;
        size_t  tFootnoteTextLen, tBlockDepotLen, tBlockSize;
        size_t  tIndex;

        TRACE_MSG("vGet8FootnotesText");

        ulBeginOfFootnotes = ulGetLong(0x18, aucHeader); /* fcMin */
        ulBeginOfFootnotes += ulGetLong(0x4c, aucHeader); /* ccpText */
        NO_DBG_HEX(ulBeginOfFootnotes);

        ulBeginFootnoteText = ulGetLong(0xb2, aucHeader); /* fcPlcffndTxt */
        NO_DBG_HEX(ulBeginFootnoteText);
        tFootnoteTextLen =
                (size_t)ulGetLong(0xb6, aucHeader); /* lcbPlcffndTxt */
        NO_DBG_DEC(tFootnoteTextLen);

        if (tFootnoteTextLen < 12) {
                DBG_MSG("No Footnote text in this document");
                return;
        }

        NO_DBG_DEC(pPPS->tTable.ulSB);
        NO_DBG_HEX(pPPS->tTable.ulSize);
        if (pPPS->tTable.ulSize == 0) {
                DBG_MSG("No footnote text information");
                return;
        }

        if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
                /* Use the Small Block Depot */
                aulBlockDepot = aulSBD;
                tBlockDepotLen = tSBDLen;
                tBlockSize = SMALL_BLOCK_SIZE;
        } else {
                /* Use the Big Block Depot */
                aulBlockDepot = aulBBD;
                tBlockDepotLen = tBBDLen;
                tBlockSize = BIG_BLOCK_SIZE;
        }
        aucBuffer = xmalloc(tFootnoteTextLen);
        if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
                        aulBlockDepot, tBlockDepotLen, tBlockSize,
                        aucBuffer, ulBeginFootnoteText, tFootnoteTextLen)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteTextLen);

        fail(tFootnoteTextLength != 0);
        tFootnoteTextLength = tFootnoteTextLen / 4 - 2;
        fail(tFootnoteTextLength == 0);

        fail(pFootnoteText != NULL);
        pFootnoteText = xcalloc(tFootnoteTextLength,
                                sizeof(footnote_local_type));

        for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
                pCurr = pFootnoteText + tIndex;
                pCurr->tInfo.szText = NULL;
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfFootnotes + ulOffset;
                NO_DBG_HEX(ulCharPos);
                NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosStart = ulCharPos;
                ulOffset = ulGetLong(tIndex * 4 + 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulCharPos = ulBeginOfFootnotes + ulOffset;
                NO_DBG_HEX(ulCharPos);
                NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
                pCurr->ulCharPosNext = ulCharPos;
                pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet8FootnotesText */

/*
 * Build the list with endnote information for Word 8/9/10 files
 */
static void
vGet8EndnotesInfo(FILE *pFile, const pps_info_type *pPPS,
        const ULONG *aulBBD, size_t tBBDLen,
        const ULONG *aulSBD, size_t tSBDLen,
        const UCHAR *aucHeader)
{
        const ULONG     *aulBlockDepot;
        UCHAR   *aucBuffer;
        ULONG   ulFileOffset, ulBeginOfText, ulOffset, ulBeginEndnoteInfo;
        size_t  tEndnoteInfoLen, tBlockDepotLen, tBlockSize;
        size_t  tIndex;

        TRACE_MSG("vGet8EndnotesInfo");

        ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
        NO_DBG_HEX(ulBeginOfText);
        ulBeginEndnoteInfo = ulGetLong(0x20a, aucHeader); /* fcPlcfendRef */
        NO_DBG_HEX(ulBeginEndnoteInfo);
        tEndnoteInfoLen = (size_t)ulGetLong(0x20e, aucHeader); /* lcbPlcfendRef */
        NO_DBG_DEC(tEndnoteInfoLen);

        if (tEndnoteInfoLen < 10) {
                DBG_MSG("No endnotes in this document");
                return;
        }

        NO_DBG_DEC(pPPS->tTable.ulSB);
        NO_DBG_HEX(pPPS->tTable.ulSize);
        if (pPPS->tTable.ulSize == 0) {
                DBG_MSG("No endnotes information");
                return;
        }

        if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
                /* Use the Small Block Depot */
                aulBlockDepot = aulSBD;
                tBlockDepotLen = tSBDLen;
                tBlockSize = SMALL_BLOCK_SIZE;
        } else {
                /* Use the Big Block Depot */
                aulBlockDepot = aulBBD;
                tBlockDepotLen = tBBDLen;
                tBlockSize = BIG_BLOCK_SIZE;
        }
        aucBuffer = xmalloc(tEndnoteInfoLen);
        if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
                        aulBlockDepot, tBlockDepotLen, tBlockSize,
                        aucBuffer, ulBeginEndnoteInfo, tEndnoteInfoLen)) {
                aucBuffer = xfree(aucBuffer);
                return;
        }
        NO_DBG_PRINT_BLOCK(aucBuffer, tEndnoteInfoLen);

        fail(tEndnoteListLength != 0);
        tEndnoteListLength = (tEndnoteInfoLen - 4) / 6;
        fail(tEndnoteListLength == 0);

        fail(aulEndnoteList != NULL);
        aulEndnoteList = xcalloc(tEndnoteListLength, sizeof(ULONG));

        for (tIndex = 0; tIndex < tEndnoteListLength; tIndex++) {
                ulOffset = ulGetLong(tIndex * 4, aucBuffer);
                NO_DBG_HEX(ulOffset);
                ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
                NO_DBG_HEX(ulFileOffset);
                aulEndnoteList[tIndex] = ulFileOffset;
        }
        aucBuffer = xfree(aucBuffer);
} /* end of vGet8EndnotesInfo */

/*
 * Build the lists with footnote and endnote information for Word 8/9/10 files
 */
static void
vGet8NotesInfo(FILE *pFile, const pps_info_type *pPPS,
        const ULONG *aulBBD, size_t tBBDLen,
        const ULONG *aulSBD, size_t tSBDLen,
        const UCHAR *aucHeader)
{
        TRACE_MSG("vGet8NotesInfo");

        vGet8FootnotesInfo(pFile, pPPS,
                        aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
        vGet8FootnotesText(pFile, pPPS,
                        aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
        vGet8EndnotesInfo(pFile, pPPS,
                        aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
} /* end of vGet8NotesInfo */

/*
 * Build the lists with footnote and endnote information
 */
void
vGetNotesInfo(FILE *pFile, const pps_info_type *pPPS,
        const ULONG *aulBBD, size_t tBBDLen,
        const ULONG *aulSBD, size_t tSBDLen,
        const UCHAR *aucHeader, int iWordVersion)
{
        TRACE_MSG("vGetNotesInfo");

        fail(pFile == NULL);
        fail(pPPS == NULL && iWordVersion >= 6);
        fail(aulBBD == NULL && tBBDLen != 0);
        fail(aulSBD == NULL && tSBDLen != 0);
        fail(aucHeader == NULL);

        switch (iWordVersion) {
        case 0:
                vGet0NotesInfo(pFile, aucHeader);
                break;
        case 1:
        case 2:
                vGet2NotesInfo(pFile, aucHeader);
                break;
        case 4:
        case 5:
                break;
        case 6:
        case 7:
                vGet6NotesInfo(pFile, pPPS->tWordDocument.ulSB,
                        aulBBD, tBBDLen, aucHeader);
                break;
        case 8:
                vGet8NotesInfo(pFile, pPPS,
                        aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
                break;
        default:
                werr(0, "Sorry, no notes information");
                break;
        }
} /* end of vGetNotesInfo */

/*
 *  vPrepareFootnoteText - prepare the footnote text
 */
void
vPrepareFootnoteText(FILE *pFile)
{ 
        footnote_local_type     *pCurr;
        size_t          tFootnote;

        fail(pFile == NULL);
        fail(pFootnoteText == NULL && tFootnoteTextLength != 0);

        if (pFootnoteText == NULL || tFootnoteTextLength == 0) {
                /* No information */
                return;
        }

        /* Fill text and useful-ness */
        for (tFootnote = 0; tFootnote < tFootnoteTextLength; tFootnote++) {
                pCurr = pFootnoteText + tFootnote;
                pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
                if (pCurr->bUseful) {
                        pCurr->tInfo.szText = szFootnoteDecryptor(pFile,
                                                        pCurr->ulCharPosStart,
                                                        pCurr->ulCharPosNext);
                } else {
                        pCurr->tInfo.szText = NULL;
                }
        }
} /* end of vPrepareFootnoteText */

/*
 * szGetFootnootText - get the text of the spefified footnote
 */
const char *
szGetFootnootText(UINT uiFootnoteIndex)
{
        if ((size_t)uiFootnoteIndex >= tFootnoteTextLength) {
                return NULL;
        }
        return pFootnoteText[uiFootnoteIndex].tInfo.szText;
} /* end of szGetFootnootText */

/*
 * Get the notetype of the note at the given fileoffset
 */
notetype_enum
eGetNotetype(ULONG ulFileOffset)
{
        size_t  tIndex;

        TRACE_MSG("eGetNotetype");

        fail(aulFootnoteList == NULL && tFootnoteListLength != 0);
        fail(aulEndnoteList == NULL && tEndnoteListLength != 0);

        /* Go for the easy answers first */
        if (tFootnoteListLength == 0 && tEndnoteListLength == 0) {
                return notetype_is_unknown;
        }
        if (tEndnoteListLength == 0) {
                return notetype_is_footnote;
        }
        if (tFootnoteListLength == 0) {
                return notetype_is_endnote;
        }
        /* No easy answer, so we search */
        for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
                if (aulFootnoteList[tIndex] == ulFileOffset) {
                        return notetype_is_footnote;
                }
        }
        for (tIndex = 0; tIndex < tEndnoteListLength; tIndex++) {
                if (aulEndnoteList[tIndex] == ulFileOffset) {
                        return notetype_is_endnote;
                }
        }
        /* Not found */
        return notetype_is_unknown;
} /* end of eGetNotetype */