home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / anwor032.zip / antiword.0.32 / wordlib.c < prev    next >
C/C++ Source or Header  |  2001-09-12  |  24KB  |  872 lines

  1. /*
  2.  * wordlib.c
  3.  * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
  4.  *
  5.  * Description:
  6.  * Deal with the internals of a MS Word file
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "antiword.h"
  13.  
  14. /* Private type for Property Set Storage entries */
  15. typedef struct pps_entry_tag {
  16.     char    szName[32];
  17.     int    iType;
  18.     int    iNext;
  19.     int    iPrev;
  20.     int    iDir;
  21.     long    lSb;
  22.     long    lSize;
  23.     int    iLevel;
  24. } pps_entry_type;
  25.  
  26.  
  27. /* Macro to make sure all such statements will be identical */
  28. #define FREE_ALL()        \
  29.     do {\
  30.         vDestroySmallBlockList();\
  31.         alRootList = xfree(alRootList);\
  32.         alSbdList = xfree(alSbdList);\
  33.         alBbdList = xfree(alBbdList);\
  34.         alSBD = xfree(alSBD);\
  35.         alBBD = xfree(alBBD);\
  36.     } while(0)
  37.  
  38.  
  39. /*
  40.  * ulReadLong - read four bytes from the given file and offset
  41.  */
  42. static unsigned long
  43. ulReadLong(FILE *pFile, long lOffset)
  44. {
  45.     unsigned char    aucBytes[4];
  46.  
  47.     fail(pFile == NULL || lOffset < 0);
  48.  
  49.     if (!bReadBytes(aucBytes, 4, lOffset, pFile)) {
  50.         werr(1, "Read long %ld not possible", lOffset);
  51.     }
  52.     return ulGetLong(0, aucBytes);
  53. } /* end of ulReadLong */
  54.  
  55. /*
  56.  * vName2String - turn the name into a proper string.
  57.  */
  58. static void
  59. vName2String(char *szName, const unsigned char *aucBytes, int iNameSize)
  60. {
  61.     char    *pcChar;
  62.     int    iIndex;
  63.  
  64.     fail(aucBytes == NULL || szName == NULL);
  65.  
  66.     if (iNameSize <= 0) {
  67.         szName[0] = '\0';
  68.         return;
  69.     }
  70.     for (iIndex = 0, pcChar = szName;
  71.          iIndex < 2 * iNameSize;
  72.          iIndex += 2, pcChar++) {
  73.         *pcChar = (char)aucBytes[iIndex];
  74.     }
  75.     szName[iNameSize - 1] = '\0';
  76. } /* end of vName2String */
  77.  
  78. /*
  79.  * tReadBlockIndices - read the Big/Small Block Depot indices
  80.  *
  81.  * Returns the number of indices read
  82.  */
  83. static size_t
  84. tReadBlockIndices(FILE *pFile, long *alBlockDepot, size_t tMaxRec, long lOffset)
  85. {
  86.     size_t    tDone;
  87.     int    iIndex;
  88.     unsigned char    aucBytes[BIG_BLOCK_SIZE];
  89.  
  90.     fail(pFile == NULL || alBlockDepot == NULL);
  91.     fail(tMaxRec == 0);
  92.     fail(lOffset < 0);
  93.  
  94.     /* Read a big block with BBD or SBD indices */
  95.     if (!bReadBytes(aucBytes, BIG_BLOCK_SIZE, lOffset, pFile)) {
  96.         werr(0, "Reading big block from %ld is not possible", lOffset);
  97.         return 0;
  98.     }
  99.     /* Split the big block into indices, an index is four bytes */
  100.     tDone = min(tMaxRec, (size_t)BIG_BLOCK_SIZE / 4);
  101.     for (iIndex = 0; iIndex < (int)tDone; iIndex++) {
  102.         alBlockDepot[iIndex] = (long)ulGetLong(4 * iIndex, aucBytes);
  103.         NO_DBG_DEC(alBlockDepot[iIndex]);
  104.     }
  105.     return tDone;
  106. } /* end of tReadBlockIndices */
  107.  
  108. /*
  109.  * bGetBBD - get the Big Block Depot indices from the index-blocks
  110.  */
  111. static BOOL
  112. bGetBBD(FILE *pFile, const long *alDepot, size_t tDepotLen,
  113.     long *alBBD, size_t tBBDLen)
  114. {
  115.     long    lBegin;
  116.     size_t    tToGo, tDone;
  117.     int    iIndex;
  118.  
  119.     fail(pFile == NULL || alDepot == NULL || alBBD == NULL);
  120.  
  121.     DBG_MSG("bGetBBD");
  122.  
  123.     tToGo = tBBDLen;
  124.     for (iIndex = 0; iIndex < (int)tDepotLen && tToGo != 0; iIndex++) {
  125.         lBegin = (alDepot[iIndex] + 1) * BIG_BLOCK_SIZE;
  126.         NO_DBG_HEX(lBegin);
  127.         tDone = tReadBlockIndices(pFile, alBBD, tToGo, lBegin);
  128.         fail(tDone > tToGo);
  129.         if (tDone == 0) {
  130.             return FALSE;
  131.         }
  132.         alBBD += tDone;
  133.         tToGo -= tDone;
  134.     }
  135.     return tToGo == 0;
  136. } /* end of bGetBBD */
  137.  
  138. /*
  139.  * bGetSBD - get the Small Block Depot indices from the index-blocks
  140.  */
  141. static BOOL
  142. bGetSBD(FILE *pFile, const long *alDepot, size_t tDepotLen,
  143.     long *alSBD, size_t tSBDLen)
  144. {
  145.     long    lBegin;
  146.     size_t    tToGo, tDone;
  147.     int    iIndex;
  148.  
  149.     fail(pFile == NULL || alDepot == NULL || alSBD == NULL);
  150.  
  151.     DBG_MSG("bGetSBD");
  152.  
  153.     tToGo = tSBDLen;
  154.     for (iIndex = 0; iIndex < (int)tDepotLen && tToGo != 0; iIndex++) {
  155.         lBegin = (alDepot[iIndex] + 1) * BIG_BLOCK_SIZE;
  156.         NO_DBG_HEX(lBegin);
  157.         tDone = tReadBlockIndices(pFile, alSBD, tToGo, lBegin);
  158.         fail(tDone > tToGo);
  159.         if (tDone == 0) {
  160.             return FALSE;
  161.         }
  162.         alSBD += tDone;
  163.         tToGo -= tDone;
  164.     }
  165.     return tToGo == 0;
  166. } /* end of bGetSBD */
  167.  
  168. /*
  169.  * vComputePPSlevels - compute the levels of the Property Set Storage entries
  170.  */
  171. static void
  172. vComputePPSlevels(pps_entry_type *atPPSlist, pps_entry_type *pNode,
  173.             int iLevel, int iRecursionLevel)
  174. {
  175.     fail(atPPSlist == NULL || pNode == NULL);
  176.     fail(iLevel < 0 || iRecursionLevel < 0);
  177.  
  178.     if (iRecursionLevel > 25) {
  179.         /* This removes the possibility of an infinite recursion */
  180.         DBG_DEC(iRecursionLevel);
  181.         return;
  182.     }
  183.     if (pNode->iLevel <= iLevel) {
  184.         /* Avoid entering a loop */
  185.         DBG_DEC(iLevel);
  186.         DBG_DEC(pNode->iLevel);
  187.         return;
  188.     }
  189.  
  190.     pNode->iLevel = iLevel;
  191.  
  192.     if (pNode->iDir != -1) {
  193.         vComputePPSlevels(atPPSlist,
  194.                 &atPPSlist[pNode->iDir],
  195.                 iLevel + 1,
  196.                 iRecursionLevel + 1);
  197.     }
  198.     if (pNode->iNext != -1) {
  199.         vComputePPSlevels(atPPSlist,
  200.                 &atPPSlist[pNode->iNext],
  201.                 iLevel,
  202.                 iRecursionLevel + 1);
  203.     }
  204.     if (pNode->iPrev != -1) {
  205.         vComputePPSlevels(atPPSlist,
  206.                 &atPPSlist[pNode->iPrev],
  207.                 iLevel,
  208.                 iRecursionLevel + 1);
  209.     }
  210. } /* end of vComputePPSlevels */
  211.  
  212. /*
  213.  * bGetPPS - search the Property Set Storage for three sets
  214.  *
  215.  * Return TRUE if the WordDocument PPS is found
  216.  */
  217. static BOOL
  218. bGetPPS(FILE *pFile,
  219.     const long *alRootList, size_t tRootListLen, pps_info_type *pPPS)
  220. {
  221.     pps_entry_type    *atPPSlist;
  222.     long    lBegin, lTmp;
  223.     size_t    tNbrOfPPS;
  224.     int    iIndex, iStartBlock, iOffset;
  225.     int    iNameSize, iRootIndex;
  226.     BOOL    bWord, bExcel;
  227.     unsigned char    aucBytes[PROPERTY_SET_STORAGE_SIZE];
  228.  
  229.     fail(pFile == NULL || pPPS == NULL || alRootList == NULL);
  230.  
  231.     DBG_MSG("bGetPPS");
  232.     NO_DBG_DEC(tRootListLen);
  233.  
  234.     bWord = FALSE;
  235.     bExcel = FALSE;
  236.     (void)memset(pPPS, 0, sizeof(*pPPS));
  237.  
  238.     /* Read and store all the Property Set Storage entries */
  239.     tNbrOfPPS = tRootListLen * BIG_BLOCK_SIZE / PROPERTY_SET_STORAGE_SIZE;
  240.     atPPSlist = xmalloc(tNbrOfPPS * sizeof(pps_entry_type));
  241.     iRootIndex = 0;
  242.     for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
  243.         lTmp = (long)iIndex * PROPERTY_SET_STORAGE_SIZE;
  244.         iStartBlock = (int)(lTmp / BIG_BLOCK_SIZE);
  245.         iOffset = (int)(lTmp % BIG_BLOCK_SIZE);
  246.         lBegin = (alRootList[iStartBlock] + 1) * BIG_BLOCK_SIZE +
  247.             iOffset;
  248.         NO_DBG_HEX(lBegin);
  249.         if (!bReadBytes(aucBytes, PROPERTY_SET_STORAGE_SIZE,
  250.                             lBegin, pFile)) {
  251.             werr(0, "Reading PPS %d is not possible", iIndex);
  252.             atPPSlist = xfree(atPPSlist);
  253.             return FALSE;
  254.         }
  255.         iNameSize = (int)usGetWord(0x40, aucBytes);
  256.         iNameSize = (iNameSize + 1) / 2;
  257.         vName2String(atPPSlist[iIndex].szName, aucBytes, iNameSize);
  258.         atPPSlist[iIndex].iType = (int)ucGetByte(0x42, aucBytes);
  259.         if (atPPSlist[iIndex].iType == 5) {
  260.             iRootIndex = iIndex;
  261.         }
  262.         atPPSlist[iIndex].iPrev = (int)ulGetLong(0x44, aucBytes);
  263.         atPPSlist[iIndex].iNext = (int)ulGetLong(0x48, aucBytes);
  264.         atPPSlist[iIndex].iDir = (int)ulGetLong(0x4c, aucBytes);
  265.         atPPSlist[iIndex].lSb = (long)ulGetLong(0x74, aucBytes);
  266.         atPPSlist[iIndex].lSize = (long)ulGetLong(0x78, aucBytes);
  267.         atPPSlist[iIndex].iLevel = INT_MAX;
  268.         if (atPPSlist[iIndex].iPrev < -1 ||
  269.             atPPSlist[iIndex].iPrev >= (int)tNbrOfPPS ||
  270.             atPPSlist[iIndex].iNext < -1 ||
  271.             atPPSlist[iIndex].iNext >= (int)tNbrOfPPS ||
  272.             atPPSlist[iIndex].iDir < -1 ||
  273.             atPPSlist[iIndex].iDir >= (int)tNbrOfPPS) {
  274.             DBG_DEC(iIndex);
  275.             DBG_DEC(atPPSlist[iIndex].iPrev);
  276.             DBG_DEC(atPPSlist[iIndex].iNext);
  277.             DBG_DEC(atPPSlist[iIndex].iDir);
  278.             DBG_DEC(tNbrOfPPS);
  279.             werr(0, "The Property Set Storage is damaged");
  280.             atPPSlist = xfree(atPPSlist);
  281.             return FALSE;
  282.         }
  283.     }
  284.  
  285. #if 0 /* defined(DEBUG) */
  286.     DBG_MSG("Before");
  287.     for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
  288.         DBG_MSG(atPPSlist[iIndex].szName);
  289.         DBG_HEX(atPPSlist[iIndex].iDir);
  290.         DBG_HEX(atPPSlist[iIndex].iPrev);
  291.         DBG_HEX(atPPSlist[iIndex].iNext);
  292.         DBG_DEC(atPPSlist[iIndex].iSb);
  293.         DBG_HEX(atPPSlist[iIndex].lSize);
  294.         DBG_DEC(atPPSlist[iIndex].iLevel);
  295.     }
  296. #endif /* DEBUG */
  297.  
  298.     /* Add level information to each entry */
  299.     vComputePPSlevels(atPPSlist, &atPPSlist[iRootIndex], 0, 0);
  300.  
  301.     /* Check the entries on level 1 for the required information */
  302.     NO_DBG_MSG("After");
  303.     for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
  304. #if 0 /* defined(DEBUG) */
  305.         DBG_MSG(atPPSlist[iIndex].szName);
  306.         DBG_HEX(atPPSlist[iIndex].iDir);
  307.         DBG_HEX(atPPSlist[iIndex].iPrev);
  308.         DBG_HEX(atPPSlist[iIndex].iNext);
  309.         DBG_DEC(atPPSlist[iIndex].iSb);
  310.         DBG_HEX(atPPSlist[iIndex].lSize);
  311.         DBG_DEC(atPPSlist[iIndex].iLevel);
  312. #endif /* DEBUG */
  313.         if (atPPSlist[iIndex].iLevel != 1 ||
  314.             atPPSlist[iIndex].iType != 2 ||
  315.             atPPSlist[iIndex].szName[0] == '\0' ||
  316.             atPPSlist[iIndex].lSize <= 0) {
  317.             continue;
  318.         }
  319.         if (pPPS->tWordDocument.lSize <= 0 &&
  320.             STREQ(atPPSlist[iIndex].szName, "WordDocument")) {
  321.             pPPS->tWordDocument.lSb = atPPSlist[iIndex].lSb;
  322.             pPPS->tWordDocument.lSize = atPPSlist[iIndex].lSize;
  323.             bWord = TRUE;
  324.         } else if (pPPS->tData.lSize <= 0 &&
  325.                STREQ(atPPSlist[iIndex].szName, "Data")) {
  326.             pPPS->tData.lSb = atPPSlist[iIndex].lSb;
  327.             pPPS->tData.lSize = atPPSlist[iIndex].lSize;
  328.         } else if (pPPS->t0Table.lSize <= 0 &&
  329.                STREQ(atPPSlist[iIndex].szName, "0Table")) {
  330.             pPPS->t0Table.lSb = atPPSlist[iIndex].lSb;
  331.             pPPS->t0Table.lSize = atPPSlist[iIndex].lSize;
  332.         } else if (pPPS->t1Table.lSize <= 0 &&
  333.                STREQ(atPPSlist[iIndex].szName, "1Table")) {
  334.             pPPS->t1Table.lSb = atPPSlist[iIndex].lSb;
  335.             pPPS->t1Table.lSize = atPPSlist[iIndex].lSize;
  336.         } else if (STREQ(atPPSlist[iIndex].szName, "Book") ||
  337.                STREQ(atPPSlist[iIndex].szName, "Workbook")) {
  338.             bExcel = TRUE;
  339.         }
  340.     }
  341.  
  342.     /* Free the space for the Property Set Storage entries */
  343.     atPPSlist = xfree(atPPSlist);
  344.  
  345.     /* Draw your conclusions */
  346.     if (bWord) {
  347.         return TRUE;
  348.     }
  349.     if (bExcel) {
  350.         werr(0, "Sorry, but this is an Excel spreadsheet");
  351.     } else {
  352.         werr(0, "This OLE file does not contain a Word document");
  353.     }
  354.     return FALSE;
  355. } /* end of bGetPPS */
  356.  
  357. /*
  358.  * vGetBbdList - make a list of the places to find big blocks
  359.  */
  360. static void
  361. vGetBbdList(FILE *pFile, int iNbr, long *alBbdList, long lOffset)
  362. {
  363.     int    iIndex;
  364.  
  365.     fail(pFile == NULL);
  366.     fail(iNbr > 127);
  367.     fail(alBbdList == NULL);
  368.     fail(lOffset < 0);
  369.  
  370.     NO_DBG_DEC(iNbr);
  371.     for (iIndex = 0; iIndex < iNbr; iIndex++) {
  372.                 alBbdList[iIndex] =
  373.                         (long)ulReadLong(pFile, lOffset + 4 * (long)iIndex);
  374.         NO_DBG_DEC(iIndex);
  375.                 NO_DBG_HEX(alBbdList[iIndex]);
  376.         }
  377. } /* end of vGetBbdList */
  378.  
  379. /*
  380.  * bGetDocumentText - make a list of the text blocks of a Word document
  381.  *
  382.  * Return TRUE when succesful, otherwise FALSE
  383.  */
  384. static BOOL
  385. bGetDocumentText(FILE *pFile, const pps_info_type *pPPS,
  386.     const long *alBBD, size_t tBBDLen,
  387.     const long *alSBD, size_t tSBDLen,
  388.     const unsigned char *aucHeader, int iWordVersion)
  389. {
  390.     long    lBeginOfText;
  391.     long    lTextLen, lFootnoteLen, lEndnoteLen;
  392.     long    lHeaderLen, lMacroLen, lAnnotationLen;
  393.     long    lTextBoxLen, lHdrTextBoxLen;
  394.     unsigned int    uiQuickSaves;
  395.     BOOL    bFarEastWord, bFastSaved, bEncrypted, bSuccess;
  396.     unsigned short    usDocStatus, usIdent;
  397.  
  398.     fail(pFile == NULL || pPPS == NULL);
  399.     fail(alBBD == NULL);
  400.     fail(alSBD == NULL);
  401.  
  402.     DBG_MSG("bGetDocumentText");
  403.  
  404.     /* Get the "magic number" from the header */
  405.     usIdent = usGetWord(0x00, aucHeader);
  406.     DBG_HEX(usIdent);
  407.     bFarEastWord = usIdent == 0x8098 || usIdent == 0x8099 ||
  408.             usIdent == 0xa697 || usIdent == 0xa699;
  409.     /* Get the status flags from the header */
  410.     usDocStatus = usGetWord(0x0a, aucHeader);
  411.     DBG_HEX(usDocStatus);
  412.     bFastSaved = (usDocStatus & BIT(2)) != 0;
  413.     uiQuickSaves = (usDocStatus & 0x00f0) >> 4;
  414.     DBG_MSG_C(bFastSaved, "This document is Fast Saved");
  415.     DBG_DEC_C(bFastSaved, uiQuickSaves);
  416.     bEncrypted = (usDocStatus & BIT(8)) != 0;
  417.     if (bEncrypted) {
  418.         werr(0, "Encrypted documents are not supported");
  419.         return FALSE;
  420.     }
  421.  
  422.     /* Get length information */
  423.     lBeginOfText = (long)ulGetLong(0x18, aucHeader);
  424.     DBG_HEX(lBeginOfText);
  425.     if (iWordVersion == 6 || iWordVersion == 7) {
  426.         lTextLen = (long)ulGetLong(0x34, aucHeader);
  427.         lFootnoteLen = (long)ulGetLong(0x38, aucHeader);
  428.         lHeaderLen = (long)ulGetLong(0x3c, aucHeader);
  429.         lMacroLen = (long)ulGetLong(0x40, aucHeader);
  430.         lAnnotationLen = (long)ulGetLong(0x44, aucHeader);
  431.         lEndnoteLen = (long)ulGetLong(0x48, aucHeader);
  432.         lTextBoxLen = (long)ulGetLong(0x4c, aucHeader);
  433.         lHdrTextBoxLen = (long)ulGetLong(0x50, aucHeader);
  434.     } else {
  435.         lTextLen = (long)ulGetLong(0x4c, aucHeader);
  436.         lFootnoteLen = (long)ulGetLong(0x50, aucHeader);
  437.         lHeaderLen = (long)ulGetLong(0x54, aucHeader);
  438.         lMacroLen = (long)ulGetLong(0x58, aucHeader);
  439.         lAnnotationLen = (long)ulGetLong(0x5c, aucHeader);
  440.         lEndnoteLen = (long)ulGetLong(0x60, aucHeader);
  441.         lTextBoxLen = (long)ulGetLong(0x64, aucHeader);
  442.         lHdrTextBoxLen = (long)ulGetLong(0x68, aucHeader);
  443.     }
  444.     DBG_DEC(lTextLen);
  445.     DBG_DEC(lFootnoteLen);
  446.     DBG_DEC(lHeaderLen);
  447.     DBG_DEC(lMacroLen);
  448.     DBG_DEC(lAnnotationLen);
  449.     DBG_DEC(lEndnoteLen);
  450.     DBG_DEC(lTextBoxLen);
  451.     DBG_DEC(lHdrTextBoxLen);
  452.  
  453.     /* Make a list of the text blocks */
  454.     switch (iWordVersion) {
  455.     case 6:
  456.     case 7:
  457.         if (bFastSaved) {
  458.             bSuccess = bGet6DocumentText(pFile,
  459.                     bFarEastWord,
  460.                     pPPS->tWordDocument.lSb,
  461.                     alBBD, tBBDLen,
  462.                     aucHeader);
  463.         } else {
  464.               bSuccess = bAddTextBlocks(lBeginOfText,
  465.                 lTextLen +
  466.                 lFootnoteLen +
  467.                 lHeaderLen + lMacroLen + lAnnotationLen +
  468.                 lEndnoteLen +
  469.                 lTextBoxLen + lHdrTextBoxLen,
  470.                 bFarEastWord,
  471.                 IGNORE_PROPMOD,
  472.                 pPPS->tWordDocument.lSb,
  473.                 alBBD, tBBDLen);
  474.         }
  475.         break;
  476.     case 8:
  477.         bSuccess = bGet8DocumentText(pFile,
  478.                 pPPS,
  479.                 alBBD, tBBDLen, alSBD, tSBDLen,
  480.                 aucHeader);
  481.         break;
  482.     default:
  483.         werr(0, "This version of Word is not supported");
  484.         bSuccess = FALSE;
  485.         break;
  486.     }
  487.  
  488.     if (bSuccess) {
  489.         vSplitBlockList(lTextLen,
  490.                 lFootnoteLen,
  491.                 lHeaderLen + lMacroLen + lAnnotationLen,
  492.                 lEndnoteLen,
  493.                 lTextBoxLen + lHdrTextBoxLen,
  494.                 !bFastSaved && iWordVersion == 8);
  495.     } else {
  496.         vDestroyTextBlockList();
  497.         werr(0, "I can't find the text of this document");
  498.     }
  499.     return bSuccess;
  500. } /* end of bGetDocumentText */
  501.  
  502. /*
  503.  * vGetDocumentData - make a list of the data blocks of a Word document
  504.  */
  505. static void
  506. vGetDocumentData(FILE *pFile, const pps_info_type *pPPS,
  507.     const long *alBBD, size_t tBBDLen,
  508.     const unsigned char *aucHeader, int iWordVersion)
  509. {
  510.     options_type    tOptions;
  511.     long    lBeginOfText;
  512.     BOOL    bFastSaved, bHasImages, bSuccess;
  513.     unsigned short    usDocStatus;
  514.  
  515.     fail(pFile == NULL);
  516.     fail(pPPS == NULL);
  517.     fail(alBBD == NULL);
  518.  
  519.     /* Get the options */
  520.     vGetOptions(&tOptions);
  521.  
  522.     /* Get the status flags from the header */
  523.     usDocStatus = usGetWord(0x0a, aucHeader);
  524.     DBG_HEX(usDocStatus);
  525.     bFastSaved = (usDocStatus & BIT(2)) != 0;
  526.     bHasImages = (usDocStatus & BIT(3)) != 0;
  527.  
  528.     if (!bHasImages ||
  529.         !tOptions.bUseOutlineFonts ||
  530.         tOptions.eImageLevel == level_no_images) {
  531.         /*
  532.          * No images in the document or text-only output or
  533.          * no images wanted, so no data blocks will be needed
  534.          */
  535.         vDestroyDataBlockList();
  536.         return;
  537.     }
  538.  
  539.     /* Get length information */
  540.     lBeginOfText = (long)ulGetLong(0x18, aucHeader);
  541.     DBG_HEX(lBeginOfText);
  542.  
  543.     /* Make a list of the data blocks */
  544.     switch (iWordVersion) {
  545.     case 6:
  546.     case 7:
  547.         /*
  548.          * The data blocks are in the text stream. The text stream
  549.          * is in "fast saved" format or "normal saved" format
  550.          */
  551.         if (bFastSaved) {
  552.             bSuccess = bGet6DocumentData(pFile,
  553.                     pPPS->tWordDocument.lSb,
  554.                     alBBD, tBBDLen,
  555.                     aucHeader);
  556.         } else {
  557.               bSuccess = bAddDataBlocks(lBeginOfText, LONG_MAX,
  558.                 pPPS->tWordDocument.lSb, alBBD, tBBDLen);
  559.         }
  560.         break;
  561.     case 8:
  562.         /*
  563.          * The data blocks are in the data stream. The data stream
  564.          * is always in "normal saved" format
  565.          */
  566.         bSuccess = bAddDataBlocks(0, LONG_MAX,
  567.                 pPPS->tData.lSb, alBBD, tBBDLen);
  568.         break;
  569.     default:
  570.         werr(0, "This version of Word is not supported");
  571.         bSuccess = FALSE;
  572.         break;
  573.     }
  574.  
  575.     if (!bSuccess) {
  576.         vDestroyDataBlockList();
  577.         werr(0, "I can't find the data of this document");
  578.     }
  579. } /* end of vGetDocumentData */
  580.  
  581. /*
  582.  * iInitDocument - initialize the document
  583.  *
  584.  * Returns the version of Word that made the document or -1
  585.  */
  586. int
  587. iInitDocument(FILE *pFile, long lFilesize)
  588. {
  589.     pps_info_type    PPS_info;
  590.     long    *alBBD, *alSBD;
  591.     long    *alRootList, *alBbdList, *alSbdList;
  592.     long    lRootStartblock, lSbdStartblock, lSBLstartblock;
  593.     long    lAdditionalBBDlist;
  594.     long    lBdbListStart, lMaxBlock, lTmp;
  595.     size_t    tBBDLen, tSBDLen, tNumBbdBlocks, tRootListLen;
  596.     int    iWordVersion, iIndex, iStart, iToGo;
  597.     int    iMaxSmallBlock;
  598.     BOOL    bSuccess;
  599.     unsigned short    usIdent;
  600.     unsigned char    aucHeader[HEADER_SIZE];
  601.  
  602.     fail(pFile == NULL);
  603.  
  604.     lMaxBlock = lFilesize / BIG_BLOCK_SIZE - 2;
  605.     DBG_DEC(lMaxBlock);
  606.     if (lMaxBlock < 1) {
  607.         return -1;
  608.     }
  609.     tBBDLen = (size_t)(lMaxBlock + 1);
  610.     tNumBbdBlocks = (size_t)ulReadLong(pFile, 0x2c);
  611.     DBG_DEC(tNumBbdBlocks);
  612.     lRootStartblock = (long)ulReadLong(pFile, 0x30);
  613.     DBG_DEC(lRootStartblock);
  614.     lSbdStartblock = (long)ulReadLong(pFile, 0x3c);
  615.     DBG_DEC(lSbdStartblock);
  616.     lAdditionalBBDlist = (long)ulReadLong(pFile, 0x44);
  617.     DBG_DEC(lAdditionalBBDlist);
  618.     DBG_HEX(lAdditionalBBDlist);
  619.     lSBLstartblock = (long)ulReadLong(pFile,
  620.         (lRootStartblock + 1) * BIG_BLOCK_SIZE + 0x74);
  621.     DBG_DEC(lSBLstartblock);
  622.     iMaxSmallBlock = (int)(ulReadLong(pFile,
  623.         (lRootStartblock + 1) *
  624.         BIG_BLOCK_SIZE + 0x78) / SMALL_BLOCK_SIZE) - 1;
  625.     DBG_DEC(iMaxSmallBlock);
  626.     tSBDLen = (size_t)(iMaxSmallBlock + 1);
  627.     /* All to be xmalloc-ed pointers to NULL */
  628.     alRootList = NULL;
  629.     alSbdList = NULL;
  630.     alBbdList = NULL;
  631.     alSBD = NULL;
  632.     alBBD = NULL;
  633. /* Big Block Depot */
  634.     alBbdList = xmalloc(tNumBbdBlocks * sizeof(long));
  635.     alBBD = xmalloc(tBBDLen * sizeof(long));
  636.     iToGo = (int)tNumBbdBlocks;
  637.     vGetBbdList(pFile, min(iToGo, 109),  alBbdList, 0x4c);
  638.     iStart = 109;
  639.     iToGo -= 109;
  640.     while (lAdditionalBBDlist != END_OF_CHAIN && iToGo > 0) {
  641.         lBdbListStart = (lAdditionalBBDlist + 1) * BIG_BLOCK_SIZE;
  642.         vGetBbdList(pFile, min(iToGo, 127),
  643.                     alBbdList + iStart, lBdbListStart);
  644.         lAdditionalBBDlist = (long)ulReadLong(pFile,
  645.                     lBdbListStart + 4 * 127);
  646.         DBG_DEC(lAdditionalBBDlist);
  647.         DBG_HEX(lAdditionalBBDlist);
  648.         iStart += 127;
  649.         iToGo -= 127;
  650.     }
  651.     if (!bGetBBD(pFile, alBbdList, tNumBbdBlocks, alBBD, tBBDLen)) {
  652.         FREE_ALL();
  653.         return -1;
  654.     }
  655.     alBbdList = xfree(alBbdList);
  656. /* Small Block Depot */
  657.     alSbdList = xmalloc(tBBDLen * sizeof(long));
  658.     alSBD = xmalloc(tSBDLen * sizeof(long));
  659.     for (iIndex = 0, lTmp = lSbdStartblock;
  660.          iIndex < (int)tBBDLen && lTmp != END_OF_CHAIN;
  661.          iIndex++, lTmp = alBBD[lTmp]) {
  662.         if (lTmp < 0 || lTmp >= (long)tBBDLen) {
  663.             DBG_DEC(lTmp);
  664.             DBG_DEC(tBBDLen);
  665.             werr(1, "The Big Block Depot is damaged");
  666.         }
  667.         alSbdList[iIndex] = lTmp;
  668.         NO_DBG_HEX(alSbdList[iIndex]);
  669.     }
  670.     if (!bGetSBD(pFile, alSbdList, tBBDLen, alSBD, tSBDLen)) {
  671.         FREE_ALL();
  672.         return -1;
  673.     }
  674.     alSbdList = xfree(alSbdList);
  675. /* Root list */
  676.     for (tRootListLen = 0, lTmp = lRootStartblock;
  677.          tRootListLen < tBBDLen && lTmp != END_OF_CHAIN;
  678.          tRootListLen++, lTmp = alBBD[lTmp]) {
  679.         if (lTmp < 0 || lTmp >= (long)tBBDLen) {
  680.             DBG_DEC(lTmp);
  681.             DBG_DEC(tBBDLen);
  682.             werr(1, "The Big Block Depot is damaged");
  683.         }
  684.     }
  685.     if (tRootListLen == 0) {
  686.         werr(0, "No Rootlist found");
  687.         FREE_ALL();
  688.         return -1;
  689.     }
  690.     alRootList = xmalloc(tRootListLen * sizeof(long));
  691.     for (iIndex = 0, lTmp = lRootStartblock;
  692.          iIndex < (int)tBBDLen && lTmp != END_OF_CHAIN;
  693.          iIndex++, lTmp = alBBD[lTmp]) {
  694.         if (lTmp < 0 || lTmp >= (long)tBBDLen) {
  695.             DBG_DEC(lTmp);
  696.             DBG_DEC(tBBDLen);
  697.             werr(1, "The Big Block Depot is damaged");
  698.         }
  699.         alRootList[iIndex] = lTmp;
  700.         NO_DBG_DEC(alRootList[iIndex]);
  701.     }
  702.     fail(tRootListLen != (size_t)iIndex);
  703.     bSuccess = bGetPPS(pFile, alRootList, tRootListLen, &PPS_info);
  704.     alRootList = xfree(alRootList);
  705.     if (!bSuccess) {
  706.         FREE_ALL();
  707.         return -1;
  708.     }
  709. /* Small block list */
  710.     if (!bCreateSmallBlockList(lSBLstartblock, alBBD, tBBDLen)) {
  711.         FREE_ALL();
  712.         return -1;
  713.     }
  714.  
  715.     if (PPS_info.tWordDocument.lSize < MIN_SIZE_FOR_BBD_USE) {
  716.         DBG_DEC(PPS_info.tWordDocument.lSize);
  717.         FREE_ALL();
  718.         werr(0, "I'm afraid the text stream of this file "
  719.             "is too small to handle.");
  720.         return -1;
  721.     }
  722.     /* Read the headerblock */
  723.     if (!bReadBuffer(pFile, PPS_info.tWordDocument.lSb,
  724.             alBBD, tBBDLen, BIG_BLOCK_SIZE,
  725.             aucHeader, 0, HEADER_SIZE)) {
  726.         FREE_ALL();
  727.         return -1;
  728.     }
  729.     usIdent = usGetWord(0x00, aucHeader);
  730.     DBG_HEX(usIdent);
  731.     fail(usIdent != 0x8098 &&    /* Word 7 for oriental languages */
  732.          usIdent != 0x8099 &&    /* Word 7 for oriental languages */
  733.          usIdent != 0xa5dc &&    /* Word 6 & 7 */
  734.          usIdent != 0xa5ec &&    /* Word 7 & 97 & 98 */
  735.          usIdent != 0xa697 &&    /* Word 7 for oriental languages */
  736.          usIdent != 0xa699);    /* Word 7 for oriental languages */
  737.     iWordVersion = iGetVersionNumber(aucHeader);
  738.     if (iWordVersion < 6) {
  739.         FREE_ALL();
  740.         werr(0, "This file is from a version of Word before Word 6.");
  741.         return -1;
  742.     }
  743.  
  744.     bSuccess = bGetDocumentText(pFile, &PPS_info,
  745.             alBBD, tBBDLen, alSBD, tSBDLen,
  746.             aucHeader, iWordVersion);
  747.     if (bSuccess) {
  748.         vGetDocumentData(pFile, &PPS_info,
  749.             alBBD, tBBDLen, aucHeader, iWordVersion);
  750.         vSetDefaultTabWidth(pFile, &PPS_info,
  751.             alBBD, tBBDLen, alSBD, tSBDLen,
  752.             aucHeader, iWordVersion);
  753.         vGetPropertyInfo(pFile, &PPS_info,
  754.             alBBD, tBBDLen, alSBD, tSBDLen,
  755.             aucHeader, iWordVersion);
  756.         vGetNotesInfo(pFile, &PPS_info,
  757.             alBBD, tBBDLen, alSBD, tSBDLen,
  758.             aucHeader, iWordVersion);
  759.     }
  760.     FREE_ALL();
  761.     return bSuccess ? iWordVersion : -1;
  762. } /* end of iInitDocument */
  763.  
  764. /*
  765.  * vFreeDocument - free a document by free-ing its parts
  766.  */
  767. void
  768. vFreeDocument(void)
  769. {
  770.     DBG_MSG("vFreeDocument");
  771.  
  772.     /* Free the memory */
  773.     vDestroyTextBlockList();
  774.     vDestroyDataBlockList();
  775.     vDestroyRowInfoList();
  776.     vDestroyStyleInfoList();
  777.     vDestroyFontInfoList();
  778.     vDestroyPicInfoList();
  779.     vDestroyPropModList();
  780.     vDestroyNotesInfoLists();
  781.     vDestroyFontTable();
  782. } /* end of vFreeDocument */
  783.  
  784. /*
  785.  * Common part of the file checking functions
  786.  */
  787. static BOOL
  788. bCheckBytes(FILE *pFile, const unsigned char *aucBytes, size_t tBytes)
  789. {
  790.     int    iIndex, iChar;
  791.  
  792.     fail(pFile == NULL || aucBytes == NULL || tBytes == 0);
  793.  
  794.     rewind(pFile);
  795.  
  796.     for (iIndex = 0; iIndex < (int)tBytes; iIndex++) {
  797.         iChar = getc(pFile);
  798.         if (iChar == EOF || iChar != (int)aucBytes[iIndex]) {
  799.             DBG_HEX(iChar);
  800.             DBG_HEX(aucBytes[iIndex]);
  801.             return FALSE;
  802.         }
  803.     }
  804.     return TRUE;
  805. } /* end of bCheckBytes */
  806.  
  807. /*
  808.  * This function checks whether the given file is or is not a Word6 (or later)
  809.  * document
  810.  */
  811. BOOL
  812. bIsSupportedWordFile(FILE *pFile, long lFilesize)
  813. {
  814.     static unsigned char    aucBytes[] =
  815.         { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
  816.  
  817.     if (pFile == NULL || lFilesize < 0) {
  818.         DBG_MSG("No proper file given");
  819.         return FALSE;
  820.     }
  821.     if (lFilesize < (long)BIG_BLOCK_SIZE * 3 ||
  822.         lFilesize % BIG_BLOCK_SIZE != 0) {
  823.         DBG_DEC(lFilesize);
  824.         DBG_MSG("File size mismatch");
  825.         return FALSE;
  826.     }
  827.     return bCheckBytes(pFile, aucBytes, elementsof(aucBytes));
  828. } /* end of bIsSupportedWordFile */
  829.  
  830. /*
  831.  * This function checks whether the given file is or is not a "Word2, 4, 5"
  832.  * document
  833.  */
  834. BOOL
  835. bIsWord245File(FILE *pFile)
  836. {
  837.     static unsigned char    aucBytes[6][8] = {
  838.         { 0x31, 0xbe, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00 },
  839.         { 0xdb, 0xa5, 0x2d, 0x00, 0x00, 0x00, 0x09, 0x04 },
  840.         { 0xdb, 0xa5, 0x2d, 0x00, 0x31, 0x40, 0x09, 0x08 },
  841.         { 0xdb, 0xa5, 0x2d, 0x00, 0x31, 0x40, 0x09, 0x0c },
  842.         { 0xfe, 0x37, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00 },
  843.         { 0xfe, 0x37, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00 },
  844.     };
  845.     int    iIndex;
  846.  
  847.     DBG_MSG("bIsWord245File");
  848.  
  849.     for (iIndex = 0; iIndex < (int)elementsof(aucBytes); iIndex++) {
  850.         if (bCheckBytes(pFile,
  851.                 aucBytes[iIndex],
  852.                 elementsof(aucBytes[iIndex]))) {
  853.             return TRUE;
  854.         }
  855.     }
  856.     return FALSE;
  857. } /* end of bIsWord245File */
  858.  
  859. /*
  860.  * This function checks whether the given file is or is not a RTF document
  861.  */
  862. BOOL
  863. bIsRtfFile(FILE *pFile)
  864. {
  865.     static unsigned char    aucBytes[] =
  866.         { '{', '\\', 'r', 't', 'f', '1' };
  867.  
  868.     DBG_MSG("bIsRtfFile");
  869.  
  870.     return bCheckBytes(pFile, aucBytes, elementsof(aucBytes));
  871. } /* end of bIsRtfFile */
  872.