/* * 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 #include #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 */