/*
* wordole.c
* Copyright (C) 1998-2004 A.J. van Os; Released under GPL
*
* Description:
* Deal with the OLE internals of a MS Word file
*/
#include <string.h>
#include "antiword.h"
/* Private type for Property Set Storage entries */
typedef struct pps_entry_tag {
ULONG ulNext;
ULONG ulPrevious;
ULONG ulDir;
ULONG ulSB;
ULONG ulSize;
int iLevel;
char szName[32];
UCHAR ucType;
} pps_entry_type;
/* Show that a PPS number or index should not be used */
#define PPS_NUMBER_INVALID 0xffffffffUL
/* Macro to make sure all such statements will be identical */
#define FREE_ALL() \
do {\
vDestroySmallBlockList();\
aulRootList = xfree(aulRootList);\
aulSbdList = xfree(aulSbdList);\
aulBbdList = xfree(aulBbdList);\
aulSBD = xfree(aulSBD);\
aulBBD = xfree(aulBBD);\
} while(0)
/*
* ulReadLong - read four bytes from the given file and offset
*/
static ULONG
ulReadLong(FILE *pFile, ULONG ulOffset)
{
UCHAR aucBytes[4];
fail(pFile == NULL);
if (!bReadBytes(aucBytes, 4, ulOffset, pFile)) {
werr(1, "Read long 0x%lx not possible", ulOffset);
}
return ulGetLong(0, aucBytes);
} /* end of ulReadLong */
/*
* vName2String - turn the name into a proper string.
*/
static void
vName2String(char *szName, const UCHAR *aucBytes, size_t tNameSize)
{
char *pcChar;
size_t tIndex;
fail(aucBytes == NULL || szName == NULL);
if (tNameSize < 2) {
szName[0] = '\0';
return;
}
for (tIndex = 0, pcChar = szName;
tIndex < 2 * tNameSize;
tIndex += 2, pcChar++) {
*pcChar = (char)aucBytes[tIndex];
}
szName[tNameSize - 1] = '\0';
} /* end of vName2String */
/*
* tReadBlockIndices - read the Big/Small Block Depot indices
*
* Returns the number of indices read
*/
static size_t
tReadBlockIndices(FILE *pFile, ULONG *aulBlockDepot,
size_t tMaxRec, ULONG ulOffset)
{
size_t tDone;
int iIndex;
UCHAR aucBytes[BIG_BLOCK_SIZE];
fail(pFile == NULL || aulBlockDepot == NULL);
fail(tMaxRec == 0);
/* Read a big block with BBD or SBD indices */
if (!bReadBytes(aucBytes, BIG_BLOCK_SIZE, ulOffset, pFile)) {
werr(0, "Reading big block from 0x%lx is not possible",
ulOffset);
return 0;
}
/* Split the big block into indices, an index is four bytes */
tDone = min(tMaxRec, (size_t)BIG_BLOCK_SIZE / 4);
for (iIndex = 0; iIndex < (int)tDone; iIndex++) {
aulBlockDepot[iIndex] = ulGetLong(4 * iIndex, aucBytes);
NO_DBG_DEC(aulBlockDepot[iIndex]);
}
return tDone;
} /* end of tReadBlockIndices */
/*
* bGetBBD - get the Big Block Depot indices from the index-blocks
*/
static BOOL
bGetBBD(FILE *pFile, const ULONG *aulDepot, size_t tDepotLen,
ULONG *aulBBD, size_t tBBDLen)
{
ULONG ulBegin;
size_t tToGo, tDone;
int iIndex;
fail(pFile == NULL || aulDepot == NULL || aulBBD == NULL);
DBG_MSG("bGetBBD");
tToGo = tBBDLen;
for (iIndex = 0; iIndex < (int)tDepotLen && tToGo != 0; iIndex++) {
ulBegin = (aulDepot[iIndex] + 1) * BIG_BLOCK_SIZE;
NO_DBG_HEX(ulBegin);
tDone = tReadBlockIndices(pFile, aulBBD, tToGo, ulBegin);
fail(tDone > tToGo);
if (tDone == 0) {
return FALSE;
}
aulBBD += tDone;
tToGo -= tDone;
}
return tToGo == 0;
} /* end of bGetBBD */
/*
* bGetSBD - get the Small Block Depot indices from the index-blocks
*/
static BOOL
bGetSBD(FILE *pFile, const ULONG *aulDepot, size_t tDepotLen,
ULONG *aulSBD, size_t tSBDLen)
{
ULONG ulBegin;
size_t tToGo, tDone;
int iIndex;
fail(pFile == NULL || aulDepot == NULL || aulSBD == NULL);
DBG_MSG("bGetSBD");
tToGo = tSBDLen;
for (iIndex = 0; iIndex < (int)tDepotLen && tToGo != 0; iIndex++) {
fail(aulDepot[iIndex] >= ULONG_MAX / BIG_BLOCK_SIZE);
ulBegin = (aulDepot[iIndex] + 1) * BIG_BLOCK_SIZE;
NO_DBG_HEX(ulBegin);
tDone = tReadBlockIndices(pFile, aulSBD, tToGo, ulBegin);
fail(tDone > tToGo);
if (tDone == 0) {
return FALSE;
}
aulSBD += tDone;
tToGo -= tDone;
}
return tToGo == 0;
} /* end of bGetSBD */
/*
* vComputePPSlevels - compute the levels of the Property Set Storage entries
*/
static void
vComputePPSlevels(pps_entry_type *atPPSlist, pps_entry_type *pNode,
int iLevel, int iRecursionLevel)
{
fail(atPPSlist == NULL || pNode == NULL);
fail(iLevel < 0 || iRecursionLevel < 0);
if (iRecursionLevel > 25) {
/* This removes the possibility of an infinite recursion */
DBG_DEC(iRecursionLevel);
return;
}
if (pNode->iLevel <= iLevel) {
/* Avoid entering a loop */
DBG_DEC(iLevel);
DBG_DEC(pNode->iLevel);
return;
}
pNode->iLevel = iLevel;
if (pNode->ulDir != PPS_NUMBER_INVALID) {
vComputePPSlevels(atPPSlist,
&atPPSlist[pNode->ulDir],
iLevel + 1,
iRecursionLevel + 1);
}
if (pNode->ulNext != PPS_NUMBER_INVALID) {
vComputePPSlevels(atPPSlist,
&atPPSlist[pNode->ulNext],
iLevel,
iRecursionLevel + 1);
}
if (pNode->ulPrevious != PPS_NUMBER_INVALID) {
vComputePPSlevels(atPPSlist,
&atPPSlist[pNode->ulPrevious],
iLevel,
iRecursionLevel + 1);
}
} /* end of vComputePPSlevels */
/*
* bGetPPS - search the Property Set Storage for three sets
*
* Return TRUE if the WordDocument PPS is found
*/
static BOOL
bGetPPS(FILE *pFile,
const ULONG *aulRootList, size_t tRootListLen, pps_info_type *pPPS)
{
pps_entry_type *atPPSlist;
ULONG ulBegin, ulOffset, ulTmp;
size_t tNbrOfPPS, tNameSize;
int iIndex, iStartBlock, iRootIndex;
BOOL bWord, bExcel;
UCHAR aucBytes[PROPERTY_SET_STORAGE_SIZE];
fail(pFile == NULL || aulRootList == NULL || pPPS == NULL);
DBG_MSG("bGetPPS");
NO_DBG_DEC(tRootListLen);
bWord = FALSE;
bExcel = FALSE;
(void)memset(pPPS, 0, sizeof(*pPPS));
/* Read and store all the Property Set Storage entries */
tNbrOfPPS = tRootListLen * BIG_BLOCK_SIZE / PROPERTY_SET_STORAGE_SIZE;
atPPSlist = xcalloc(tNbrOfPPS, sizeof(pps_entry_type));
iRootIndex = 0;
for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
ulTmp = (ULONG)iIndex * PROPERTY_SET_STORAGE_SIZE;
iStartBlock = (int)(ulTmp / BIG_BLOCK_SIZE);
ulOffset = ulTmp % BIG_BLOCK_SIZE;
ulBegin = (aulRootList[iStartBlock] + 1) * BIG_BLOCK_SIZE +
ulOffset;
NO_DBG_HEX(ulBegin);
if (!bReadBytes(aucBytes, PROPERTY_SET_STORAGE_SIZE,
ulBegin, pFile)) {
werr(0, "Reading PPS %d is not possible", iIndex);
atPPSlist = xfree(atPPSlist);
return FALSE;
}
tNameSize = (size_t)usGetWord(0x40, aucBytes);
tNameSize = (tNameSize + 1) / 2;
vName2String(atPPSlist[iIndex].szName, aucBytes, tNameSize);
atPPSlist[iIndex].ucType = ucGetByte(0x42, aucBytes);
if (atPPSlist[iIndex].ucType == 5) {
iRootIndex = iIndex;
}
atPPSlist[iIndex].ulPrevious = ulGetLong(0x44, aucBytes);
atPPSlist[iIndex].ulNext = ulGetLong(0x48, aucBytes);
atPPSlist[iIndex].ulDir = ulGetLong(0x4c, aucBytes);
atPPSlist[iIndex].ulSB = ulGetLong(0x74, aucBytes);
atPPSlist[iIndex].ulSize = ulGetLong(0x78, aucBytes);
atPPSlist[iIndex].iLevel = INT_MAX;
if ((atPPSlist[iIndex].ulPrevious >= (ULONG)tNbrOfPPS &&
atPPSlist[iIndex].ulPrevious != PPS_NUMBER_INVALID) ||
(atPPSlist[iIndex].ulNext >= (ULONG)tNbrOfPPS &&
atPPSlist[iIndex].ulNext != PPS_NUMBER_INVALID) ||
(atPPSlist[iIndex].ulDir >= (ULONG)tNbrOfPPS &&
atPPSlist[iIndex].ulDir != PPS_NUMBER_INVALID)) {
DBG_DEC(iIndex);
DBG_DEC(atPPSlist[iIndex].ulPrevious);
DBG_DEC(atPPSlist[iIndex].ulNext);
DBG_DEC(atPPSlist[iIndex].ulDir);
DBG_DEC(tNbrOfPPS);
werr(0, "The Property Set Storage is damaged");
atPPSlist = xfree(atPPSlist);
return FALSE;
}
}
#if 0 /* defined(DEBUG) */
DBG_MSG("Before");
for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
DBG_MSG(atPPSlist[iIndex].szName);
DBG_HEX(atPPSlist[iIndex].ulDir);
DBG_HEX(atPPSlist[iIndex].ulPrevious);
DBG_HEX(atPPSlist[iIndex].ulNext);
DBG_DEC(atPPSlist[iIndex].ulSB);
DBG_HEX(atPPSlist[iIndex].ulSize);
DBG_DEC(atPPSlist[iIndex].iLevel);
}
#endif /* DEBUG */
/* Add level information to each entry */
vComputePPSlevels(atPPSlist, &atPPSlist[iRootIndex], 0, 0);
/* Check the entries on level 1 for the required information */
NO_DBG_MSG("After");
for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
#if 0 /* defined(DEBUG) */
DBG_MSG(atPPSlist[iIndex].szName);
DBG_HEX(atPPSlist[iIndex].ulDir);
DBG_HEX(atPPSlist[iIndex].ulPrevious);
DBG_HEX(atPPSlist[iIndex].ulNext);
DBG_DEC(atPPSlist[iIndex].ulSB);
DBG_HEX(atPPSlist[iIndex].ulSize);
DBG_DEC(atPPSlist[iIndex].iLevel);
#endif /* DEBUG */
if (atPPSlist[iIndex].iLevel != 1 ||
atPPSlist[iIndex].ucType != 2 ||
atPPSlist[iIndex].szName[0] == '\0' ||
atPPSlist[iIndex].ulSize == 0) {
/* This entry can be ignored */
continue;
}
if (pPPS->tWordDocument.ulSize == 0 &&
STREQ(atPPSlist[iIndex].szName, "WordDocument")) {
pPPS->tWordDocument.ulSB = atPPSlist[iIndex].ulSB;
pPPS->tWordDocument.ulSize = atPPSlist[iIndex].ulSize;
bWord = TRUE;
} else if (pPPS->tData.ulSize == 0 &&
STREQ(atPPSlist[iIndex].szName, "Data")) {
pPPS->tData.ulSB = atPPSlist[iIndex].ulSB;
pPPS->tData.ulSize = atPPSlist[iIndex].ulSize;
} else if (pPPS->t0Table.ulSize == 0 &&
STREQ(atPPSlist[iIndex].szName, "0Table")) {
pPPS->t0Table.ulSB = atPPSlist[iIndex].ulSB;
pPPS->t0Table.ulSize = atPPSlist[iIndex].ulSize;
} else if (pPPS->t1Table.ulSize == 0 &&
STREQ(atPPSlist[iIndex].szName, "1Table")) {
pPPS->t1Table.ulSB = atPPSlist[iIndex].ulSB;
pPPS->t1Table.ulSize = atPPSlist[iIndex].ulSize;
} else if (pPPS->tSummaryInfo.ulSize == 0 &&
STREQ(atPPSlist[iIndex].szName,
"\005SummaryInformation")) {
pPPS->tSummaryInfo.ulSB = atPPSlist[iIndex].ulSB;
pPPS->tSummaryInfo.ulSize = atPPSlist[iIndex].ulSize;
} else if (pPPS->tDocSummaryInfo.ulSize == 0 &&
STREQ(atPPSlist[iIndex].szName,
"\005DocumentSummaryInformation")) {
pPPS->tDocSummaryInfo.ulSB = atPPSlist[iIndex].ulSB;
pPPS->tDocSummaryInfo.ulSize = atPPSlist[iIndex].ulSize;
} else if (STREQ(atPPSlist[iIndex].szName, "Book") ||
STREQ(atPPSlist[iIndex].szName, "Workbook")) {
bExcel = TRUE;
}
}
/* Free the space for the Property Set Storage entries */
atPPSlist = xfree(atPPSlist);
/* Draw your conclusions */
if (bWord) {
return TRUE;
}
if (bExcel) {
werr(0, "Sorry, but this is an Excel spreadsheet");
} else {
werr(0, "This OLE file does not contain a Word document");
}
return FALSE;
} /* end of bGetPPS */
/*
* vGetBbdList - make a list of the places to find big blocks
*/
static void
vGetBbdList(FILE *pFile, int iNbr, ULONG *aulBbdList, ULONG ulOffset)
{
int iIndex;
fail(pFile == NULL);
fail(iNbr > 127);
fail(aulBbdList == NULL);
NO_DBG_DEC(iNbr);
for (iIndex = 0; iIndex < iNbr; iIndex++) {
aulBbdList[iIndex] =
ulReadLong(pFile, ulOffset + 4 * (ULONG)iIndex);
NO_DBG_DEC(iIndex);
NO_DBG_HEX(aulBbdList[iIndex]);
}
} /* end of vGetBbdList */
/*
* bGetDocumentText - make a list of the text blocks of a Word document
*
* Return TRUE when succesful, otherwise FALSE
*/
static BOOL
bGetDocumentText(FILE *pFile, const pps_info_type *pPPS,
const ULONG *aulBBD, size_t tBBDLen,
const ULONG *aulSBD, size_t tSBDLen,
const UCHAR *aucHeader, int iWordVersion)
{
ULONG ulBeginOfText;
ULONG ulTextLen, ulFootnoteLen, ulEndnoteLen;
ULONG ulHdrFtrLen, ulMacroLen, ulAnnotationLen;
ULONG ulTextBoxLen, ulHdrTextBoxLen;
UINT uiQuickSaves;
BOOL bFarEastWord, bTemplate, bFastSaved, bEncrypted, bSuccess;
USHORT usIdent, usDocStatus;
fail(pFile == NULL || pPPS == NULL);
fail(aulBBD == NULL);
fail(aulSBD == NULL);
DBG_MSG("bGetDocumentText");
/* Get the "magic number" from the header */
usIdent = usGetWord(0x00, aucHeader);
DBG_HEX(usIdent);
bFarEastWord = usIdent == 0x8098 || usIdent == 0x8099 ||
usIdent == 0xa697 || usIdent == 0xa699;
/* Get the status flags from the header */
usDocStatus = usGetWord(0x0a, aucHeader);
DBG_HEX(usDocStatus);
bTemplate = (usDocStatus & BIT(0)) != 0;
DBG_MSG_C(bTemplate, "This document is a Template");
bFastSaved = (usDocStatus & BIT(2)) != 0;
uiQuickSaves = (UINT)(usDocStatus & 0x00f0) >> 4;
DBG_MSG_C(bFastSaved, "This document is Fast Saved");
DBG_DEC_C(bFastSaved, uiQuickSaves);
bEncrypted = (usDocStatus & BIT(8)) != 0;
if (bEncrypted) {
werr(0, "Encrypted documents are not supported");
return FALSE;
}
/* Get length information */
ulBeginOfText = ulGetLong(0x18, aucHeader);
DBG_HEX(ulBeginOfText);
switch (iWordVersion) {
case 6:
case 7:
ulTextLen = ulGetLong(0x34, aucHeader);
ulFootnoteLen = ulGetLong(0x38, aucHeader);
ulHdrFtrLen = ulGetLong(0x3c, aucHeader);
ulMacroLen = ulGetLong(0x40, aucHeader);
ulAnnotationLen = ulGetLong(0x44, aucHeader);
ulEndnoteLen = ulGetLong(0x48, aucHeader);
ulTextBoxLen = ulGetLong(0x4c, aucHeader);
ulHdrTextBoxLen = ulGetLong(0x50, aucHeader);
break;
case 8:
ulTextLen = ulGetLong(0x4c, aucHeader);
ulFootnoteLen = ulGetLong(0x50, aucHeader);
ulHdrFtrLen = ulGetLong(0x54, aucHeader);
ulMacroLen = ulGetLong(0x58, aucHeader);
ulAnnotationLen = ulGetLong(0x5c, aucHeader);
ulEndnoteLen = ulGetLong(0x60, aucHeader);
ulTextBoxLen = ulGetLong(0x64, aucHeader);
ulHdrTextBoxLen = ulGetLong(0x68, aucHeader);
break;
default:
werr(0, "This version of Word is not supported");
return FALSE;
}
DBG_DEC(ulTextLen);
DBG_DEC(ulFootnoteLen);
DBG_DEC(ulHdrFtrLen);
DBG_DEC(ulMacroLen);
DBG_DEC(ulAnnotationLen);
DBG_DEC(ulEndnoteLen);
DBG_DEC(ulTextBoxLen);
DBG_DEC(ulHdrTextBoxLen);
/* Make a list of the text blocks */
switch (iWordVersion) {
case 6:
case 7:
if (bFastSaved) {
bSuccess = bGet6DocumentText(pFile,
bFarEastWord,
pPPS->tWordDocument.ulSB,
aulBBD, tBBDLen,
aucHeader);
} else {
bSuccess = bAddTextBlocks(ulBeginOfText,
ulTextLen +
ulFootnoteLen +
ulHdrFtrLen +
ulMacroLen + ulAnnotationLen +
ulEndnoteLen +
ulTextBoxLen + ulHdrTextBoxLen,
bFarEastWord,
IGNORE_PROPMOD,
pPPS->tWordDocument.ulSB,
aulBBD, tBBDLen);
}
break;
case 8:
bSuccess = bGet8DocumentText(pFile,
pPPS,
aulBBD, tBBDLen, aulSBD, tSBDLen,
aucHeader);
break;
default:
werr(0, "This version of Word is not supported");
bSuccess = FALSE;
break;
}
if (bSuccess) {
vSplitBlockList(pFile,
ulTextLen,
ulFootnoteLen,
ulHdrFtrLen,
ulMacroLen,
ulAnnotationLen,
ulEndnoteLen,
ulTextBoxLen,
ulHdrTextBoxLen,
!bFastSaved && iWordVersion == 8);
} else {
vDestroyTextBlockList();
werr(0, "I can't find the text of this document");
}
return bSuccess;
} /* end of bGetDocumentText */
/*
* vGetDocumentData - make a list of the data blocks of a Word document
*/
static void
vGetDocumentData(FILE *pFile, const pps_info_type *pPPS,
const ULONG *aulBBD, size_t tBBDLen,
const UCHAR *aucHeader, int iWordVersion)
{
options_type tOptions;
ULONG ulBeginOfText;
BOOL bFastSaved, bHasImages, bSuccess;
USHORT usDocStatus;
fail(pFile == NULL);
fail(pPPS == NULL);
fail(aulBBD == NULL);
/* Get the options */
vGetOptions(&tOptions);
/* Get the status flags from the header */
usDocStatus = usGetWord(0x0a, aucHeader);
DBG_HEX(usDocStatus);
bFastSaved = (usDocStatus & BIT(2)) != 0;
bHasImages = (usDocStatus & BIT(3)) != 0;
if (!bHasImages ||
tOptions.eConversionType == conversion_text ||
tOptions.eConversionType == conversion_fmt_text ||
tOptions.eConversionType == conversion_xml ||
tOptions.eImageLevel == level_no_images) {
/*
* No images in the document or text-only output or
* no images wanted, so no data blocks will be needed
*/
vDestroyDataBlockList();
return;
}
/* Get length information */
ulBeginOfText = ulGetLong(0x18, aucHeader);
DBG_HEX(ulBeginOfText);
/* Make a list of the data blocks */
switch (iWordVersion) {
case 6:
case 7:
/*
* The data blocks are in the text stream. The text stream
* is in "fast saved" format or "normal saved" format
*/
if (bFastSaved) {
bSuccess = bGet6DocumentData(pFile,
pPPS->tWordDocument.ulSB,
aulBBD, tBBDLen,
aucHeader);
} else {
bSuccess = bAddDataBlocks(ulBeginOfText,
(ULONG)LONG_MAX,
pPPS->tWordDocument.ulSB,
aulBBD, tBBDLen);
}
break;
case 8:
/*
* The data blocks are in the data stream. The data stream
* is always in "normal saved" format
*/
bSuccess = bAddDataBlocks(0, (ULONG)LONG_MAX,
pPPS->tData.ulSB, aulBBD, tBBDLen);
break;
default:
werr(0, "This version of Word is not supported");
bSuccess = FALSE;
break;
}
if (!bSuccess) {
vDestroyDataBlockList();
werr(0, "I can't find the data of this document");
}
} /* end of vGetDocumentData */
/*
* iInitDocumentOLE - initialize an OLE document
*
* Returns the version of Word that made the document or -1
*/
int
iInitDocumentOLE(FILE *pFile, long lFilesize)
{
pps_info_type PPS_info;
ULONG *aulBBD, *aulSBD;
ULONG *aulRootList, *aulBbdList, *aulSbdList;
ULONG ulBdbListStart, ulAdditionalBBDlist;
ULONG ulRootStartblock, ulSbdStartblock, ulSBLstartblock;
ULONG ulStart, ulTmp;
long lMaxBlock;
size_t tBBDLen, tSBDLen, tNumBbdBlocks, tRootListLen;
int iWordVersion, iIndex, iToGo;
BOOL bSuccess;
USHORT usIdent, usDocStatus;
UCHAR aucHeader[HEADER_SIZE];
fail(pFile == NULL);
lMaxBlock = lFilesize / BIG_BLOCK_SIZE - 2;
DBG_DEC(lMaxBlock);
if (lMaxBlock < 1) {
return -1;
}
tBBDLen = (size_t)(lMaxBlock + 1);
tNumBbdBlocks = (size_t)ulReadLong(pFile, 0x2c);
DBG_DEC(tNumBbdBlocks);
ulRootStartblock = ulReadLong(pFile, 0x30);
DBG_DEC(ulRootStartblock);
ulSbdStartblock = ulReadLong(pFile, 0x3c);
DBG_DEC(ulSbdStartblock);
ulAdditionalBBDlist = ulReadLong(pFile, 0x44);
DBG_HEX(ulAdditionalBBDlist);
ulSBLstartblock = ulReadLong(pFile,
(ulRootStartblock + 1) * BIG_BLOCK_SIZE + 0x74);
DBG_DEC(ulSBLstartblock);
tSBDLen = (size_t)(ulReadLong(pFile,
(ulRootStartblock + 1) * BIG_BLOCK_SIZE + 0x78) /
SMALL_BLOCK_SIZE);
/* All to be xcalloc-ed pointers to NULL */
aulRootList = NULL;
aulSbdList = NULL;
aulBbdList = NULL;
aulSBD = NULL;
aulBBD = NULL;
/* Big Block Depot */
aulBbdList = xcalloc(tNumBbdBlocks, sizeof(ULONG));
aulBBD = xcalloc(tBBDLen, sizeof(ULONG));
iToGo = (int)tNumBbdBlocks;
vGetBbdList(pFile, min(iToGo, 109), aulBbdList, 0x4c);
ulStart = 109;
iToGo -= 109;
while (ulAdditionalBBDlist != END_OF_CHAIN && iToGo > 0) {
ulBdbListStart = (ulAdditionalBBDlist + 1) * BIG_BLOCK_SIZE;
vGetBbdList(pFile, min(iToGo, 127),
aulBbdList + ulStart, ulBdbListStart);
ulAdditionalBBDlist = ulReadLong(pFile,
ulBdbListStart + 4 * 127);
DBG_DEC(ulAdditionalBBDlist);
DBG_HEX(ulAdditionalBBDlist);
ulStart += 127;
iToGo -= 127;
}
if (!bGetBBD(pFile, aulBbdList, tNumBbdBlocks, aulBBD, tBBDLen)) {
FREE_ALL();
return -1;
}
aulBbdList = xfree(aulBbdList);
/* Small Block Depot */
aulSbdList = xcalloc(tBBDLen, sizeof(ULONG));
aulSBD = xcalloc(tSBDLen, sizeof(ULONG));
for (iIndex = 0, ulTmp = ulSbdStartblock;
iIndex < (int)tBBDLen && ulTmp != END_OF_CHAIN;
iIndex++, ulTmp = aulBBD[ulTmp]) {
if (ulTmp >= (ULONG)tBBDLen) {
DBG_DEC(ulTmp);
DBG_DEC(tBBDLen);
werr(1, "The Big Block Depot is damaged");
}
aulSbdList[iIndex] = ulTmp;
NO_DBG_HEX(aulSbdList[iIndex]);
}
if (!bGetSBD(pFile, aulSbdList, tBBDLen, aulSBD, tSBDLen)) {
FREE_ALL();
return -1;
}
aulSbdList = xfree(aulSbdList);
/* Root list */
for (tRootListLen = 0, ulTmp = ulRootStartblock;
tRootListLen < tBBDLen && ulTmp != END_OF_CHAIN;
tRootListLen++, ulTmp = aulBBD[ulTmp]) {
if (ulTmp >= (ULONG)tBBDLen) {
DBG_DEC(ulTmp);
DBG_DEC(tBBDLen);
werr(1, "The Big Block Depot is damaged");
}
}
if (tRootListLen == 0) {
werr(0, "No Rootlist found");
FREE_ALL();
return -1;
}
aulRootList = xcalloc(tRootListLen, sizeof(ULONG));
for (iIndex = 0, ulTmp = ulRootStartblock;
iIndex < (int)tBBDLen && ulTmp != END_OF_CHAIN;
iIndex++, ulTmp = aulBBD[ulTmp]) {
if (ulTmp >= (ULONG)tBBDLen) {
DBG_DEC(ulTmp);
DBG_DEC(tBBDLen);
werr(1, "The Big Block Depot is damaged");
}
aulRootList[iIndex] = ulTmp;
NO_DBG_DEC(aulRootList[iIndex]);
}
fail(tRootListLen != (size_t)iIndex);
bSuccess = bGetPPS(pFile, aulRootList, tRootListLen, &PPS_info);
aulRootList = xfree(aulRootList);
if (!bSuccess) {
FREE_ALL();
return -1;
}
/* Small block list */
if (!bCreateSmallBlockList(ulSBLstartblock, aulBBD, tBBDLen)) {
FREE_ALL();
return -1;
}
if (PPS_info.tWordDocument.ulSize < MIN_SIZE_FOR_BBD_USE) {
DBG_DEC(PPS_info.tWordDocument.ulSize);
FREE_ALL();
werr(0, "I'm afraid the text stream of this file "
"is too small to handle.");
return -1;
}
/* Read the headerblock */
if (!bReadBuffer(pFile, PPS_info.tWordDocument.ulSB,
aulBBD, tBBDLen, BIG_BLOCK_SIZE,
aucHeader, 0, HEADER_SIZE)) {
FREE_ALL();
return -1;
}
usIdent = usGetWord(0x00, aucHeader);
DBG_HEX(usIdent);
fail(usIdent != 0x8098 && /* Word 7 for oriental languages */
usIdent != 0x8099 && /* Word 7 for oriental languages */
usIdent != 0xa5dc && /* Word 6 & 7 */
usIdent != 0xa5ec && /* Word 7 & 97 & 98 */
usIdent != 0xa697 && /* Word 7 for oriental languages */
usIdent != 0xa699); /* Word 7 for oriental languages */
iWordVersion = iGetVersionNumber(aucHeader);
if (iWordVersion < 6) {
FREE_ALL();
werr(0, "This file is from a version of Word before Word 6.");
return -1;
}
/* Get the status flags from the header */
usDocStatus = usGetWord(0x0a, aucHeader);
if (usDocStatus & BIT(9)) {
PPS_info.tTable = PPS_info.t1Table;
} else {
PPS_info.tTable = PPS_info.t0Table;
}
/* Clean the entries that should not be used */
memset(&PPS_info.t0Table, 0, sizeof(PPS_info.t0Table));
memset(&PPS_info.t1Table, 0, sizeof(PPS_info.t1Table));
bSuccess = bGetDocumentText(pFile, &PPS_info,
aulBBD, tBBDLen, aulSBD, tSBDLen,
aucHeader, iWordVersion);
if (bSuccess) {
vGetDocumentData(pFile, &PPS_info,
aulBBD, tBBDLen, aucHeader, iWordVersion);
vGetPropertyInfo(pFile, &PPS_info,
aulBBD, tBBDLen, aulSBD, tSBDLen,
aucHeader, iWordVersion);
vSetDefaultTabWidth(pFile, &PPS_info,
aulBBD, tBBDLen, aulSBD, tSBDLen,
aucHeader, iWordVersion);
vGetNotesInfo(pFile, &PPS_info,
aulBBD, tBBDLen, aulSBD, tSBDLen,
aucHeader, iWordVersion);
}
FREE_ALL();
return bSuccess ? iWordVersion : -1;
} /* end of iInitDocumentOLE */
|