mirror of
https://github.com/simon987/antiword.git
synced 2025-04-10 13:06:41 +00:00
375 lines
8.7 KiB
C
375 lines
8.7 KiB
C
/*
|
|
* datalist.c
|
|
* Copyright (C) 2000-2002 A.J. van Os; Released under GPL
|
|
*
|
|
* Description:
|
|
* Build, read and destroy a list of Word data blocks
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include "antiword.h"
|
|
|
|
#if defined(__riscos)
|
|
#define EIO 42
|
|
#endif /* __riscos */
|
|
|
|
|
|
/*
|
|
* Private structure to hide the way the information
|
|
* is stored from the rest of the program
|
|
*/
|
|
typedef struct data_mem_tag {
|
|
data_block_type tInfo;
|
|
struct data_mem_tag *pNext;
|
|
} data_mem_type;
|
|
|
|
/* Variable to describe the start of the data block list */
|
|
static data_mem_type *pAnchor = NULL;
|
|
/* Variable needed to read the data block list */
|
|
static data_mem_type *pBlockLast = NULL;
|
|
/* Variable needed to read the data block list */
|
|
static data_mem_type *pBlockCurrent = NULL;
|
|
static ULONG ulBlockOffset = 0;
|
|
static size_t tByteNext = 0;
|
|
/* Last block read */
|
|
static UCHAR aucBlock[BIG_BLOCK_SIZE];
|
|
|
|
|
|
/*
|
|
* vDestroyDataBlockList - destroy the data block list
|
|
*/
|
|
void
|
|
vDestroyDataBlockList(void)
|
|
{
|
|
data_mem_type *pCurr, *pNext;
|
|
|
|
DBG_MSG("vDestroyDataBlockList");
|
|
|
|
pCurr = pAnchor;
|
|
while (pCurr != NULL) {
|
|
pNext = pCurr->pNext;
|
|
pCurr = xfree(pCurr);
|
|
pCurr = pNext;
|
|
}
|
|
pAnchor = NULL;
|
|
/* Reset all the control variables */
|
|
pBlockLast = NULL;
|
|
pBlockCurrent = NULL;
|
|
ulBlockOffset = 0;
|
|
tByteNext = 0;
|
|
} /* end of vDestroyDataBlockList */
|
|
|
|
/*
|
|
* bAdd2DataBlockList - add an element to the data block list
|
|
*
|
|
* Returns TRUE when successful, otherwise FALSE
|
|
*/
|
|
BOOL
|
|
bAdd2DataBlockList(const data_block_type *pDataBlock)
|
|
{
|
|
data_mem_type *pListMember;
|
|
|
|
fail(pDataBlock == NULL);
|
|
fail(pDataBlock->ulFileOffset == FC_INVALID);
|
|
fail(pDataBlock->ulDataPos == CP_INVALID);
|
|
fail(pDataBlock->ulLength == 0);
|
|
|
|
NO_DBG_MSG("bAdd2DataBlockList");
|
|
NO_DBG_HEX(pDataBlock->ulFileOffset);
|
|
NO_DBG_HEX(pDataBlock->ulDataPos);
|
|
NO_DBG_HEX(pDataBlock->ulLength);
|
|
|
|
if (pDataBlock->ulFileOffset == FC_INVALID ||
|
|
pDataBlock->ulDataPos == CP_INVALID ||
|
|
pDataBlock->ulLength == 0) {
|
|
werr(0, "Software (datablock) error");
|
|
return FALSE;
|
|
}
|
|
/* Check for continuous blocks */
|
|
if (pBlockLast != NULL &&
|
|
pBlockLast->tInfo.ulFileOffset +
|
|
pBlockLast->tInfo.ulLength == pDataBlock->ulFileOffset &&
|
|
pBlockLast->tInfo.ulDataPos +
|
|
pBlockLast->tInfo.ulLength == pDataBlock->ulDataPos) {
|
|
/* These are continous blocks */
|
|
pBlockLast->tInfo.ulLength += pDataBlock->ulLength;
|
|
return TRUE;
|
|
}
|
|
/* Make a new block */
|
|
pListMember = xmalloc(sizeof(data_mem_type));
|
|
/* Add the block to the data list */
|
|
pListMember->tInfo = *pDataBlock;
|
|
pListMember->pNext = NULL;
|
|
if (pAnchor == NULL) {
|
|
pAnchor = pListMember;
|
|
} else {
|
|
fail(pBlockLast == NULL);
|
|
pBlockLast->pNext = pListMember;
|
|
}
|
|
pBlockLast = pListMember;
|
|
return TRUE;
|
|
} /* end of bAdd2DataBlockList */
|
|
|
|
/*
|
|
* ulGetDataOffset - get the offset in the data block list
|
|
*
|
|
* Get the fileoffset the current position in the data block list
|
|
*/
|
|
ULONG
|
|
ulGetDataOffset(FILE *pFile)
|
|
{
|
|
return pBlockCurrent->tInfo.ulFileOffset + ulBlockOffset + tByteNext;
|
|
} /* end of ulGetDataOffset */
|
|
|
|
/*
|
|
* bSetDataOffset - set the offset in the data block list
|
|
*
|
|
* Make the given fileoffset the current position in the data block list
|
|
*/
|
|
BOOL
|
|
bSetDataOffset(FILE *pFile, ULONG ulFileOffset)
|
|
{
|
|
data_mem_type *pCurr;
|
|
size_t tReadLen;
|
|
|
|
DBG_HEX(ulFileOffset);
|
|
|
|
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
|
|
if (ulFileOffset < pCurr->tInfo.ulFileOffset ||
|
|
ulFileOffset >= pCurr->tInfo.ulFileOffset +
|
|
pCurr->tInfo.ulLength) {
|
|
/* The file offset is not in this block */
|
|
continue;
|
|
}
|
|
/* Compute the maximum number of bytes to read */
|
|
tReadLen = (size_t)(pCurr->tInfo.ulFileOffset +
|
|
pCurr->tInfo.ulLength -
|
|
ulFileOffset);
|
|
/* Compute the real number of bytes to read */
|
|
if (tReadLen > sizeof(aucBlock)) {
|
|
tReadLen = sizeof(aucBlock);
|
|
}
|
|
/* Read the bytes */
|
|
if (!bReadBytes(aucBlock, tReadLen, ulFileOffset, pFile)) {
|
|
return FALSE;
|
|
}
|
|
/* Set the control variables */
|
|
pBlockCurrent = pCurr;
|
|
ulBlockOffset = ulFileOffset - pCurr->tInfo.ulFileOffset;
|
|
tByteNext = 0;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
} /* end of bSetDataOffset */
|
|
|
|
/*
|
|
* iNextByte - get the next byte from the data block list
|
|
*/
|
|
int
|
|
iNextByte(FILE *pFile)
|
|
{
|
|
ULONG ulReadOff;
|
|
size_t tReadLen;
|
|
|
|
fail(pBlockCurrent == NULL);
|
|
|
|
if (tByteNext >= sizeof(aucBlock) ||
|
|
ulBlockOffset + tByteNext >= pBlockCurrent->tInfo.ulLength) {
|
|
if (ulBlockOffset + sizeof(aucBlock) <
|
|
pBlockCurrent->tInfo.ulLength) {
|
|
/* Same block, next part */
|
|
ulBlockOffset += sizeof(aucBlock);
|
|
} else {
|
|
/* Next block, first part */
|
|
pBlockCurrent = pBlockCurrent->pNext;
|
|
ulBlockOffset = 0;
|
|
}
|
|
if (pBlockCurrent == NULL) {
|
|
/* Past the last part of the last block */
|
|
errno = EIO;
|
|
return EOF;
|
|
}
|
|
tReadLen = (size_t)
|
|
(pBlockCurrent->tInfo.ulLength - ulBlockOffset);
|
|
if (tReadLen > sizeof(aucBlock)) {
|
|
tReadLen = sizeof(aucBlock);
|
|
}
|
|
ulReadOff = pBlockCurrent->tInfo.ulFileOffset + ulBlockOffset;
|
|
if (!bReadBytes(aucBlock, tReadLen, ulReadOff, pFile)) {
|
|
errno = EIO;
|
|
return EOF;
|
|
}
|
|
tByteNext = 0;
|
|
}
|
|
return (int)aucBlock[tByteNext++];
|
|
} /* end of iNextByte */
|
|
|
|
/*
|
|
* usNextWord - get the next word from the data block list
|
|
*
|
|
* Read a two byte value in Little Endian order, that means MSB last
|
|
*
|
|
* All return values can be valid so errno is set in case of error
|
|
*/
|
|
USHORT
|
|
usNextWord(FILE *pFile)
|
|
{
|
|
USHORT usLSB, usMSB;
|
|
|
|
usLSB = (USHORT)iNextByte(pFile);
|
|
if (usLSB == (USHORT)EOF) {
|
|
errno = EIO;
|
|
return (USHORT)EOF;
|
|
}
|
|
usMSB = (USHORT)iNextByte(pFile);
|
|
if (usMSB == (USHORT)EOF) {
|
|
DBG_MSG("usNextWord: Unexpected EOF");
|
|
errno = EIO;
|
|
return (USHORT)EOF;
|
|
}
|
|
return (usMSB << 8) | usLSB;
|
|
} /* end of usNextWord */
|
|
|
|
/*
|
|
* ulNextLong - get the next long from the data block list
|
|
*
|
|
* Read a four byte value in Little Endian order, that means MSW last
|
|
*
|
|
* All return values can be valid so errno is set in case of error
|
|
*/
|
|
ULONG
|
|
ulNextLong(FILE *pFile)
|
|
{
|
|
ULONG ulLSW, ulMSW;
|
|
|
|
ulLSW = (ULONG)usNextWord(pFile);
|
|
if (ulLSW == (ULONG)EOF) {
|
|
errno = EIO;
|
|
return (ULONG)EOF;
|
|
}
|
|
ulMSW = (ULONG)usNextWord(pFile);
|
|
if (ulMSW == (ULONG)EOF) {
|
|
DBG_MSG("ulNextLong: Unexpected EOF");
|
|
errno = EIO;
|
|
return (ULONG)EOF;
|
|
}
|
|
return (ulMSW << 16) | ulLSW;
|
|
} /* end of ulNextLong */
|
|
|
|
/*
|
|
* usNextWordBE - get the next two byte value
|
|
*
|
|
* Read a two byte value in Big Endian order, that means MSB first
|
|
*
|
|
* All return values can be valid so errno is set in case of error
|
|
*/
|
|
USHORT
|
|
usNextWordBE(FILE *pFile)
|
|
{
|
|
USHORT usLSB, usMSB;
|
|
|
|
usMSB = (USHORT)iNextByte(pFile);
|
|
if (usMSB == (USHORT)EOF) {
|
|
errno = EIO;
|
|
return (USHORT)EOF;
|
|
}
|
|
usLSB = (USHORT)iNextByte(pFile);
|
|
if (usLSB == (USHORT)EOF) {
|
|
DBG_MSG("usNextWordBE: Unexpected EOF");
|
|
errno = EIO;
|
|
return (USHORT)EOF;
|
|
}
|
|
return (usMSB << 8) | usLSB;
|
|
} /* end of usNextWordBE */
|
|
|
|
/*
|
|
* ulNextLongBE - get the next four byte value
|
|
*
|
|
* Read a four byte value in Big Endian order, that means MSW first
|
|
*
|
|
* All return values can be valid so errno is set in case of error
|
|
*/
|
|
ULONG
|
|
ulNextLongBE(FILE *pFile)
|
|
{
|
|
ULONG ulLSW, ulMSW;
|
|
|
|
ulMSW = (ULONG)usNextWordBE(pFile);
|
|
if (ulMSW == (ULONG)EOF) {
|
|
errno = EIO;
|
|
return (ULONG)EOF;
|
|
}
|
|
ulLSW = (ULONG)usNextWordBE(pFile);
|
|
if (ulLSW == (ULONG)EOF) {
|
|
DBG_MSG("ulNextLongBE: Unexpected EOF");
|
|
errno = EIO;
|
|
return (ULONG)EOF;
|
|
}
|
|
return (ulMSW << 16) | ulLSW;
|
|
} /* end of ulNextLongBE */
|
|
|
|
/*
|
|
* tSkipBytes - skip over the given number of bytes
|
|
*
|
|
* Returns the number of skipped bytes
|
|
*/
|
|
size_t
|
|
tSkipBytes(FILE *pFile, size_t tToSkip)
|
|
{
|
|
size_t tToGo, tMaxMove, tMove;
|
|
|
|
fail(pFile == NULL);
|
|
fail(pBlockCurrent == NULL);
|
|
|
|
tToGo = tToSkip;
|
|
while (tToGo != 0) {
|
|
/* Goto the end of the current block */
|
|
tMaxMove = min(sizeof(aucBlock) - tByteNext,
|
|
(size_t)(pBlockCurrent->tInfo.ulLength -
|
|
ulBlockOffset - tByteNext));
|
|
tMove = min(tMaxMove, tToGo);
|
|
tByteNext += tMove;
|
|
tToGo -= tMove;
|
|
if (tToGo != 0) {
|
|
/* Goto the next block */
|
|
if (iNextByte(pFile) == EOF) {
|
|
return tToSkip - tToGo;
|
|
}
|
|
tToGo--;
|
|
}
|
|
}
|
|
return tToSkip;
|
|
} /* end of tSkipBytes */
|
|
|
|
/*
|
|
* Translate a data position to an offset in the file.
|
|
* Logical to physical offset.
|
|
*
|
|
* Returns: FC_INVALID: in case of error
|
|
* otherwise: the computed file offset
|
|
*/
|
|
ULONG
|
|
ulDataPos2FileOffset(ULONG ulDataPos)
|
|
{
|
|
data_mem_type *pCurr;
|
|
|
|
fail(ulDataPos == CP_INVALID);
|
|
|
|
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
|
|
if (ulDataPos < pCurr->tInfo.ulDataPos ||
|
|
ulDataPos >= pCurr->tInfo.ulDataPos +
|
|
pCurr->tInfo.ulLength) {
|
|
/* The data offset is not in this block, try the next */
|
|
continue;
|
|
}
|
|
/* The data offset is in the current block */
|
|
return pCurr->tInfo.ulFileOffset +
|
|
ulDataPos -
|
|
pCurr->tInfo.ulDataPos;
|
|
}
|
|
/* Passed beyond the end of the list */
|
|
DBG_HEX_C(ulDataPos != 0, ulDataPos);
|
|
return FC_INVALID;
|
|
} /* end of ulDataPos2FileOffset */
|