/*
* blocklist.c
* Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
*
* Description:
* Build, read and destroy the lists of Word "text" blocks
*/
#include <stdlib.h>
#include "antiword.h"
/*
* Private structure to hide the way the information
* is stored from the rest of the program
*/
typedef struct list_mem_tag {
text_block_type tInfo;
struct list_mem_tag *pNext;
} list_mem_type;
typedef struct readinfo_tag {
list_mem_type *pBlockCurrent;
ULONG ulBlockOffset;
size_t tByteNext;
UCHAR aucBlock[BIG_BLOCK_SIZE];
} readinfo_type;
/* Variables to describe the start of the block lists */
static list_mem_type *pTextAnchor = NULL;
static list_mem_type *pFootnoteAnchor = NULL;
static list_mem_type *pHdrFtrAnchor = NULL;
static list_mem_type *pMacroAnchor = NULL;
static list_mem_type *pAnnotationAnchor = NULL;
static list_mem_type *pEndnoteAnchor = NULL;
static list_mem_type *pTextBoxAnchor = NULL;
static list_mem_type *pHdrTextBoxAnchor = NULL;
/* Variable needed to build the block list */
static list_mem_type *pBlockLast = NULL;
/* Variable needed to read the block lists */
static readinfo_type tOthers = { NULL, 0, 0, };
static readinfo_type tHdrFtr = { NULL, 0, 0, };
static readinfo_type tFootnote = { NULL, 0, 0, };
/*
* pFreeOneList - free a text block list
*
* Will always return NULL
*/
static list_mem_type *
pFreeOneList(list_mem_type *pAnchor)
{
list_mem_type *pCurr, *pNext;
pCurr = pAnchor;
while (pCurr != NULL) {
pNext = pCurr->pNext;
pCurr = xfree(pCurr);
pCurr = pNext;
}
return NULL;
} /* end of pFreeOneList */
/*
* vDestroyTextBlockList - destroy the text block lists
*/
void
vDestroyTextBlockList(void)
{
DBG_MSG("vDestroyTextBlockList");
/* Free the lists one by one */
pTextAnchor = pFreeOneList(pTextAnchor);
pFootnoteAnchor = pFreeOneList(pFootnoteAnchor);
pHdrFtrAnchor = pFreeOneList(pHdrFtrAnchor);
pMacroAnchor = pFreeOneList(pMacroAnchor);
pAnnotationAnchor = pFreeOneList(pAnnotationAnchor);
pEndnoteAnchor = pFreeOneList(pEndnoteAnchor);
pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
/* Reset all the controle variables */
pBlockLast = NULL;
tOthers.pBlockCurrent = NULL;
tHdrFtr.pBlockCurrent = NULL;
tFootnote.pBlockCurrent = NULL;
} /* end of vDestroyTextBlockList */
/*
* bAdd2TextBlockList - add an element to the text block list
*
* returns: TRUE when successful, otherwise FALSE
*/
BOOL
bAdd2TextBlockList(const text_block_type *pTextBlock)
{
list_mem_type *pListMember;
fail(pTextBlock == NULL);
fail(pTextBlock->ulFileOffset == FC_INVALID);
fail(pTextBlock->ulCharPos == CP_INVALID);
fail(pTextBlock->ulLength == 0);
fail(pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength));
NO_DBG_MSG("bAdd2TextBlockList");
NO_DBG_HEX(pTextBlock->ulFileOffset);
NO_DBG_HEX(pTextBlock->ulCharPos);
NO_DBG_HEX(pTextBlock->ulLength);
NO_DBG_DEC(pTextBlock->bUsesUnicode);
NO_DBG_DEC(pTextBlock->usPropMod);
if (pTextBlock->ulFileOffset == FC_INVALID ||
pTextBlock->ulCharPos == CP_INVALID ||
pTextBlock->ulLength == 0 ||
(pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength))) {
werr(0, "Software (textblock) error");
return FALSE;
}
/*
* Check for continuous blocks of the same character size and
* the same properties modifier
*/
if (pBlockLast != NULL &&
pBlockLast->tInfo.ulFileOffset +
pBlockLast->tInfo.ulLength == pTextBlock->ulFileOffset &&
pBlockLast->tInfo.ulCharPos +
pBlockLast->tInfo.ulLength == pTextBlock->ulCharPos &&
pBlockLast->tInfo.bUsesUnicode == pTextBlock->bUsesUnicode &&
pBlockLast->tInfo.usPropMod == pTextBlock->usPropMod) {
/* These are continous blocks */
pBlockLast->tInfo.ulLength += pTextBlock->ulLength;
return TRUE;
}
/* Make a new block */
pListMember = xmalloc(sizeof(list_mem_type));
/* Add the block to the list */
pListMember->tInfo = *pTextBlock;
pListMember->pNext = NULL;
if (pTextAnchor == NULL) {
pTextAnchor = pListMember;
} else {
fail(pBlockLast == NULL);
pBlockLast->pNext = pListMember;
}
pBlockLast = pListMember;
return TRUE;
} /* end of bAdd2TextBlockList */
/*
* vSpitList - Split the list in two
*/
static void
vSpitList(list_mem_type **ppAnchorCurr, list_mem_type **ppAnchorNext,
ULONG ulListLen)
{
list_mem_type *pCurr;
long lCharsToGo, lBytesTooFar;
fail(ppAnchorCurr == NULL);
fail(ppAnchorNext == NULL);
fail(ulListLen > (ULONG)LONG_MAX);
pCurr = NULL;
lCharsToGo = (long)ulListLen;
lBytesTooFar = -1;
if (ulListLen != 0) {
DBG_DEC(ulListLen);
for (pCurr = *ppAnchorCurr;
pCurr != NULL;
pCurr = pCurr->pNext) {
NO_DBG_DEC(pCurr->tInfo.ulLength);
fail(pCurr->tInfo.ulLength == 0);
fail(pCurr->tInfo.ulLength > (ULONG)LONG_MAX);
if (pCurr->tInfo.bUsesUnicode) {
fail(odd(pCurr->tInfo.ulLength));
lCharsToGo -= (long)(pCurr->tInfo.ulLength / 2);
if (lCharsToGo < 0) {
lBytesTooFar = -2 * lCharsToGo;
}
} else {
lCharsToGo -= (long)pCurr->tInfo.ulLength;
if (lCharsToGo < 0) {
lBytesTooFar = -lCharsToGo;
}
}
if (lCharsToGo <= 0) {
break;
}
}
}
/* Split the list */
if (ulListLen == 0) {
/* Current blocklist is empty */
*ppAnchorNext = *ppAnchorCurr;
*ppAnchorCurr = NULL;
} else if (pCurr == NULL) {
/* No blocks for the next list */
*ppAnchorNext = NULL;
} else if (lCharsToGo == 0) {
/* Move the integral number of blocks to the next list */
*ppAnchorNext = pCurr->pNext;
pCurr->pNext = NULL;
} else {
/* Split the part current block list, part next block list */
DBG_DEC(lBytesTooFar);
fail(lBytesTooFar <= 0);
*ppAnchorNext = xmalloc(sizeof(list_mem_type));
DBG_HEX(pCurr->tInfo.ulFileOffset);
(*ppAnchorNext)->tInfo.ulFileOffset =
pCurr->tInfo.ulFileOffset +
pCurr->tInfo.ulLength -
lBytesTooFar;
DBG_HEX((*ppAnchorNext)->tInfo.ulFileOffset);
DBG_HEX(pCurr->tInfo.ulCharPos);
(*ppAnchorNext)->tInfo.ulCharPos =
pCurr->tInfo.ulCharPos +
pCurr->tInfo.ulLength -
lBytesTooFar;
DBG_HEX((*ppAnchorNext)->tInfo.ulCharPos);
(*ppAnchorNext)->tInfo.ulLength = (ULONG)lBytesTooFar;
pCurr->tInfo.ulLength -= (ULONG)lBytesTooFar;
(*ppAnchorNext)->tInfo.bUsesUnicode = pCurr->tInfo.bUsesUnicode;
(*ppAnchorNext)->tInfo.usPropMod = pCurr->tInfo.usPropMod;
/* Move the integral number of blocks to the next list */
(*ppAnchorNext)->pNext = pCurr->pNext;
pCurr->pNext = NULL;
}
} /* end of vSpitList */
#if defined(DEBUG) || defined(__riscos)
/*
* ulComputeListLength - compute the length of a list
*
* returns the list length in characters
*/
static ULONG
ulComputeListLength(const list_mem_type *pAnchor)
{
const list_mem_type *pCurr;
ULONG ulTotal;
ulTotal = 0;
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
fail(pCurr->tInfo.ulLength == 0);
if (pCurr->tInfo.bUsesUnicode) {
fail(odd(pCurr->tInfo.ulLength));
ulTotal += pCurr->tInfo.ulLength / 2;
} else {
ulTotal += pCurr->tInfo.ulLength;
}
}
return ulTotal;
} /* end of ulComputeListLength */
#endif /* DEBUG || __riscos */
#if defined(DEBUG)
/*
* vCheckList - check the number of bytes in a block list
*/
static void
vCheckList(const list_mem_type *pAnchor, ULONG ulListLen, char *szMsg)
{
ULONG ulTotal;
ulTotal = ulComputeListLength(pAnchor);
DBG_DEC(ulTotal);
if (ulTotal != ulListLen) {
DBG_DEC(ulListLen);
werr(1, szMsg);
}
} /* end of vCheckList */
#endif /* DEBUG */
/*
* bIsEmptyBox - check to see if the given text box is empty
*/
static BOOL
bIsEmptyBox(FILE *pFile, const list_mem_type *pAnchor)
{
const list_mem_type *pCurr;
size_t tIndex, tSize;
UCHAR *aucBuffer;
char cChar;
fail(pFile == NULL);
if (pAnchor == NULL) {
return TRUE;
}
aucBuffer = NULL;
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
fail(pCurr->tInfo.ulLength == 0);
tSize = (size_t)pCurr->tInfo.ulLength;
#if defined(__dos) && !defined(__DJGPP__)
if (pCurr->tInfo.ulLength > 0xffffUL) {
tSize = 0xffff;
}
#endif /* __dos && !__DJGPP__ */
fail(aucBuffer != NULL);
aucBuffer = xmalloc(tSize);
if (!bReadBytes(aucBuffer, tSize,
pCurr->tInfo.ulFileOffset, pFile)) {
aucBuffer = xfree(aucBuffer);
return FALSE;
}
for (tIndex = 0; tIndex < tSize; tIndex++) {
cChar = (char)aucBuffer[tIndex];
switch (cChar) {
case '\0': case '\r': case '\n':
case '\f': case '\t': case '\v':
case ' ':
break;
default:
aucBuffer = xfree(aucBuffer);
return FALSE;
}
}
aucBuffer = xfree(aucBuffer);
}
fail(aucBuffer != NULL);
return TRUE;
} /* end of bIsEmptyBox */
/*
* vSplitBlockList - split the block list in the various parts
*
* Split the blocklist in a Text block list, a Footnote block list, a
* HeaderFooter block list, a Macro block list, an Annotation block list,
* an Endnote block list, a TextBox list and a HeaderTextBox list.
*
* NOTE:
* The various ul*Len input parameters are given in characters, but the
* length of the blocks are in bytes.
*/
void
vSplitBlockList(FILE *pFile, ULONG ulTextLen, ULONG ulFootnoteLen,
ULONG ulHdrFtrLen, ULONG ulMacroLen, ULONG ulAnnotationLen,
ULONG ulEndnoteLen, ULONG ulTextBoxLen, ULONG ulHdrTextBoxLen,
BOOL bMustExtend)
{
list_mem_type *apAnchors[8];
list_mem_type *pGarbageAnchor, *pCurr;
size_t tIndex;
DBG_MSG("vSplitBlockList");
pGarbageAnchor = NULL;
DBG_MSG_C(ulTextLen != 0, "Text block list");
vSpitList(&pTextAnchor, &pFootnoteAnchor, ulTextLen);
DBG_MSG_C(ulFootnoteLen != 0, "Footnote block list");
vSpitList(&pFootnoteAnchor, &pHdrFtrAnchor, ulFootnoteLen);
DBG_MSG_C(ulHdrFtrLen != 0, "Header/Footer block list");
vSpitList(&pHdrFtrAnchor, &pMacroAnchor, ulHdrFtrLen);
DBG_MSG_C(ulMacroLen != 0, "Macro block list");
vSpitList(&pMacroAnchor, &pAnnotationAnchor, ulMacroLen);
DBG_MSG_C(ulAnnotationLen != 0, "Annotation block list");
vSpitList(&pAnnotationAnchor, &pEndnoteAnchor, ulAnnotationLen);
DBG_MSG_C(ulEndnoteLen != 0, "Endnote block list");
vSpitList(&pEndnoteAnchor, &pTextBoxAnchor, ulEndnoteLen);
DBG_MSG_C(ulTextBoxLen != 0, "Textbox block list");
vSpitList(&pTextBoxAnchor, &pHdrTextBoxAnchor, ulTextBoxLen);
DBG_MSG_C(ulHdrTextBoxLen != 0, "HeaderTextbox block list");
vSpitList(&pHdrTextBoxAnchor, &pGarbageAnchor, ulHdrTextBoxLen);
/* Free the garbage block list, this should not be needed */
DBG_DEC_C(pGarbageAnchor != NULL, pGarbageAnchor->tInfo.ulLength);
pGarbageAnchor = pFreeOneList(pGarbageAnchor);
#if defined(DEBUG)
vCheckList(pTextAnchor, ulTextLen, "Software error (Text)");
vCheckList(pFootnoteAnchor, ulFootnoteLen, "Software error (Footnote)");
vCheckList(pHdrFtrAnchor, ulHdrFtrLen, "Software error (Hdr/Ftr)");
vCheckList(pMacroAnchor, ulMacroLen, "Software error (Macro)");
vCheckList(pAnnotationAnchor, ulAnnotationLen,
"Software error (Annotation)");
vCheckList(pEndnoteAnchor, ulEndnoteLen, "Software error (Endnote)");
vCheckList(pTextBoxAnchor, ulTextBoxLen, "Software error (TextBox)");
vCheckList(pHdrTextBoxAnchor, ulHdrTextBoxLen,
"Software error (HdrTextBox)");
#endif /* DEBUG */
/* Remove the list if the text box is empty */
if (bIsEmptyBox(pFile, pTextBoxAnchor)) {
pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
}
if (bIsEmptyBox(pFile, pHdrTextBoxAnchor)) {
pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
}
if (!bMustExtend) {
return;
}
/*
* All blocks (except the last one) must have a length that
* is a multiple of the Big Block Size
*/
apAnchors[0] = pTextAnchor;
apAnchors[1] = pFootnoteAnchor;
apAnchors[2] = pHdrFtrAnchor;
apAnchors[3] = pMacroAnchor;
apAnchors[4] = pAnnotationAnchor;
apAnchors[5] = pEndnoteAnchor;
apAnchors[6] = pTextBoxAnchor;
apAnchors[7] = pHdrTextBoxAnchor;
for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
for (pCurr = apAnchors[tIndex];
pCurr != NULL;
pCurr = pCurr->pNext) {
if (pCurr->pNext != NULL &&
pCurr->tInfo.ulLength % BIG_BLOCK_SIZE != 0) {
DBG_DEC(tIndex);
DBG_HEX(pCurr->tInfo.ulFileOffset);
DBG_HEX(pCurr->tInfo.ulCharPos);
DBG_DEC(pCurr->tInfo.ulLength);
pCurr->tInfo.ulLength /= BIG_BLOCK_SIZE;
pCurr->tInfo.ulLength++;
pCurr->tInfo.ulLength *= BIG_BLOCK_SIZE;
DBG_DEC(pCurr->tInfo.ulLength);
}
}
}
} /* end of vSplitBlockList */
#if defined(__riscos)
/*
* ulGetDocumentLength - get the total character length of the printable lists
*
* returns: The total number of characters
*/
ULONG
ulGetDocumentLength(void)
{
long ulTotal;
DBG_MSG("ulGetDocumentLength");
ulTotal = ulComputeListLength(pTextAnchor);
ulTotal += ulComputeListLength(pFootnoteAnchor);
ulTotal += ulComputeListLength(pEndnoteAnchor);
ulTotal += ulComputeListLength(pTextBoxAnchor);
ulTotal += ulComputeListLength(pHdrTextBoxAnchor);
DBG_DEC(ulTotal);
return ulTotal;
} /* end of ulGetDocumentLength */
#endif /* __riscos */
#if 0
/*
* bExistsHdrFtr - are there headers and/or footers?
*/
BOOL
bExistsHdrFtr(void)
{
return pHdrFtrAnchor != NULL &&
pHdrFtrAnchor->tInfo.ulLength != 0;
} /* end of bExistsHdrFtr */
#endif
/*
* bExistsTextBox - is there a text box?
*/
BOOL
bExistsTextBox(void)
{
return pTextBoxAnchor != NULL &&
pTextBoxAnchor->tInfo.ulLength != 0;
} /* end of bExistsTextBox */
/*
* bExistsHdrTextBox - is there a header text box?
*/
BOOL
bExistsHdrTextBox(void)
{
return pHdrTextBoxAnchor != NULL &&
pHdrTextBoxAnchor->tInfo.ulLength != 0;
} /* end of bExistsHdrTextBox */
/*
* usGetNextByte - get the next byte from the specified block list
*/
static USHORT
usGetNextByte(FILE *pFile, readinfo_type *pInfoCurrent, list_mem_type *pAnchor,
ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
{
ULONG ulReadOff;
size_t tReadLen;
fail(pInfoCurrent == NULL);
if (pInfoCurrent->pBlockCurrent == NULL ||
pInfoCurrent->tByteNext >= sizeof(pInfoCurrent->aucBlock) ||
pInfoCurrent->ulBlockOffset + pInfoCurrent->tByteNext >=
pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
if (pInfoCurrent->pBlockCurrent == NULL) {
/* First block, first part */
pInfoCurrent->pBlockCurrent = pAnchor;
pInfoCurrent->ulBlockOffset = 0;
} else if (pInfoCurrent->ulBlockOffset +
sizeof(pInfoCurrent->aucBlock) <
pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
/* Same block, next part */
pInfoCurrent->ulBlockOffset +=
sizeof(pInfoCurrent->aucBlock);
} else {
/* Next block, first part */
pInfoCurrent->pBlockCurrent =
pInfoCurrent->pBlockCurrent->pNext;
pInfoCurrent->ulBlockOffset = 0;
}
if (pInfoCurrent->pBlockCurrent == NULL) {
/* Past the last part of the last block */
return (USHORT)EOF;
}
tReadLen = (size_t)
(pInfoCurrent->pBlockCurrent->tInfo.ulLength -
pInfoCurrent->ulBlockOffset);
if (tReadLen > sizeof(pInfoCurrent->aucBlock)) {
tReadLen = sizeof(pInfoCurrent->aucBlock);
}
ulReadOff = pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
pInfoCurrent->ulBlockOffset;
if (!bReadBytes(pInfoCurrent->aucBlock,
tReadLen, ulReadOff, pFile)) {
/* Don't read from this list any longer */
pInfoCurrent->pBlockCurrent = NULL;
return (USHORT)EOF;
}
pInfoCurrent->tByteNext = 0;
}
if (pulFileOffset != NULL) {
*pulFileOffset =
pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
pInfoCurrent->ulBlockOffset +
pInfoCurrent->tByteNext;
}
if (pulCharPos != NULL) {
*pulCharPos =
pInfoCurrent->pBlockCurrent->tInfo.ulCharPos +
pInfoCurrent->ulBlockOffset +
pInfoCurrent->tByteNext;
}
if (pusPropMod != NULL) {
*pusPropMod = pInfoCurrent->pBlockCurrent->tInfo.usPropMod;
}
return (USHORT)pInfoCurrent->aucBlock[pInfoCurrent->tByteNext++];
} /* end of usGetNextByte */
/*
* usGetNextChar - get the next character from the specified block list
*/
static USHORT
usGetNextChar(FILE *pFile, list_id_enum eListID,
ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
{
readinfo_type *pReadinfo;
list_mem_type *pAnchor;
USHORT usLSB, usMSB;
switch (eListID) {
case text_list:
pReadinfo = &tOthers;
pAnchor = pTextAnchor;
break;
case footnote_list:
pReadinfo = &tFootnote;
pAnchor = pFootnoteAnchor;
break;
case hdrftr_list:
pReadinfo = &tHdrFtr;
pAnchor = pHdrFtrAnchor;
break;
case endnote_list:
pReadinfo = &tOthers;
pAnchor = pEndnoteAnchor;
break;
case textbox_list:
pReadinfo = &tOthers;
pAnchor = pTextBoxAnchor;
break;
case hdrtextbox_list:
pReadinfo = &tOthers;
pAnchor = pHdrTextBoxAnchor;
break;
default:
DBG_DEC(eListID);
return (USHORT)EOF;
}
usLSB = usGetNextByte(pFile, pReadinfo, pAnchor,
pulFileOffset, pulCharPos, pusPropMod);
if (usLSB == (USHORT)EOF) {
return (USHORT)EOF;
}
fail(pReadinfo->pBlockCurrent == NULL);
if (pReadinfo->pBlockCurrent->tInfo.bUsesUnicode) {
usMSB = usGetNextByte(pFile,
pReadinfo, pAnchor, NULL, NULL, NULL);
} else {
usMSB = 0x00;
}
if (usMSB == (USHORT)EOF) {
DBG_MSG("usGetNextChar: Unexpected EOF");
DBG_HEX_C(pulFileOffset != NULL, *pulFileOffset);
DBG_HEX_C(pulCharPos != NULL, *pulCharPos);
return (USHORT)EOF;
}
return (usMSB << 8) | usLSB;
} /* end of usGetNextChar */
/*
* usNextChar - get the next character from the given block list
*/
USHORT
usNextChar(FILE *pFile, list_id_enum eListID,
ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
{
USHORT usRetVal;
fail(pFile == NULL);
usRetVal = usGetNextChar(pFile, eListID,
pulFileOffset, pulCharPos, pusPropMod);
if (usRetVal == (USHORT)EOF) {
if (pulFileOffset != NULL) {
*pulFileOffset = FC_INVALID;
}
if (pulCharPos != NULL) {
*pulCharPos = CP_INVALID;
}
if (pusPropMod != NULL) {
*pusPropMod = IGNORE_PROPMOD;
}
}
return usRetVal;
} /* end of usNextChar */
/*
* usToHdrFtrPosition - Go to a character position in header/foorter list
*
* Returns the character found on the specified character position
*/
USHORT
usToHdrFtrPosition(FILE *pFile, ULONG ulCharPos)
{
ULONG ulCharPosCurr;
USHORT usChar;
tHdrFtr.pBlockCurrent = NULL; /* To reset the header/footer list */
do {
usChar = usNextChar(pFile,
hdrftr_list, NULL, &ulCharPosCurr, NULL);
} while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
return usChar;
} /* end of usToHdrFtrPosition */
/*
* usToFootnotePosition - Go to a character position in footnote list
*
* Returns the character found on the specified character position
*/
USHORT
usToFootnotePosition(FILE *pFile, ULONG ulCharPos)
{
ULONG ulCharPosCurr;
USHORT usChar;
tFootnote.pBlockCurrent = NULL; /* To reset the footnote list */
do {
usChar = usNextChar(pFile,
footnote_list, NULL, &ulCharPosCurr, NULL);
} while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
return usChar;
} /* end of usToFootnotePosition */
/*
* Convert a character position to an offset in the file.
* Logical to physical offset.
*
* Returns: FC_INVALID: in case of error
* otherwise: the computed file offset
*/
ULONG
ulCharPos2FileOffsetX(ULONG ulCharPos, list_id_enum *peListID)
{
static list_id_enum eListIDs[8] = {
text_list, footnote_list, hdrftr_list,
macro_list, annotation_list, endnote_list,
textbox_list, hdrtextbox_list,
};
list_mem_type *apAnchors[8];
list_mem_type *pCurr;
list_id_enum eListGuess;
ULONG ulBestGuess;
size_t tIndex;
fail(peListID == NULL);
if (ulCharPos == CP_INVALID) {
*peListID = no_list;
return FC_INVALID;
}
apAnchors[0] = pTextAnchor;
apAnchors[1] = pFootnoteAnchor;
apAnchors[2] = pHdrFtrAnchor;
apAnchors[3] = pMacroAnchor;
apAnchors[4] = pAnnotationAnchor;
apAnchors[5] = pEndnoteAnchor;
apAnchors[6] = pTextBoxAnchor;
apAnchors[7] = pHdrTextBoxAnchor;
eListGuess = no_list; /* Best guess is no list */
ulBestGuess = FC_INVALID; /* Best guess is "file offset not found" */
for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
for (pCurr = apAnchors[tIndex];
pCurr != NULL;
pCurr = pCurr->pNext) {
if (ulCharPos == pCurr->tInfo.ulCharPos +
pCurr->tInfo.ulLength &&
pCurr->pNext != NULL) {
/*
* The character position is one beyond this
* block, so we guess it's the first byte of
* the next block (if there is a next block)
*/
eListGuess= eListIDs[tIndex];
ulBestGuess = pCurr->pNext->tInfo.ulFileOffset;
}
if (ulCharPos < pCurr->tInfo.ulCharPos ||
ulCharPos >= pCurr->tInfo.ulCharPos +
pCurr->tInfo.ulLength) {
/* Character position is not in this block */
continue;
}
/* The character position is in the current block */
*peListID = eListIDs[tIndex];
return pCurr->tInfo.ulFileOffset +
ulCharPos - pCurr->tInfo.ulCharPos;
}
}
/* Passed beyond the end of the last list */
NO_DBG_HEX(ulCharPos);
NO_DBG_HEX(ulBestGuess);
*peListID = eListGuess;
return ulBestGuess;
} /* end of ulCharPos2FileOffsetX */
/*
* Convert a character position to an offset in the file.
* Logical to physical offset.
*
* Returns: FC_INVALID: in case of error
* otherwise: the computed file offset
*/
ULONG
ulCharPos2FileOffset(ULONG ulCharPos)
{
list_id_enum eListID;
return ulCharPos2FileOffsetX(ulCharPos, &eListID);
} /* end of ulCharPos2FileOffset */
/*
* Convert an offset in the header/footer list to a character position.
*
* Returns: CP_INVALID: in case of error
* otherwise: the computed character position
*/
ULONG
ulHdrFtrOffset2CharPos(ULONG ulHdrFtrOffset)
{
list_mem_type *pCurr;
ULONG ulOffset;
ulOffset = ulHdrFtrOffset;
for (pCurr = pHdrFtrAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
if (ulOffset >= pCurr->tInfo.ulLength) {
/* The offset is not in this block */
ulOffset -= pCurr->tInfo.ulLength;
continue;
}
return pCurr->tInfo.ulCharPos + ulOffset;
}
return CP_INVALID;
} /* end of ulHdrFtrOffset2CharPos */
/*
* Get the sequence number beloning to the given file offset
*
* Returns the sequence number
*/
ULONG
ulGetSeqNumber(ULONG ulFileOffset)
{
list_mem_type *pCurr;
ULONG ulSeq;
if (ulFileOffset == FC_INVALID) {
return FC_INVALID;
}
ulSeq = 0;
for (pCurr = pTextAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
if (ulFileOffset >= pCurr->tInfo.ulFileOffset &&
ulFileOffset < pCurr->tInfo.ulFileOffset +
pCurr->tInfo.ulLength) {
/* The file offset is within the current textblock */
return ulSeq + ulFileOffset - pCurr->tInfo.ulFileOffset;
}
ulSeq += pCurr->tInfo.ulLength;
}
return FC_INVALID;
} /* end of ulGetSeqNumber */
|