home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / anwor032.zip / antiword.0.32 / word2text.c < prev    next >
C/C++ Source or Header  |  2001-10-05  |  26KB  |  1,025 lines

  1. /*
  2.  * word2text.c
  3.  * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
  4.  *
  5.  * Description:
  6.  * MS Word to text functions
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #if defined(__riscos)
  14. #include "visdelay.h"
  15. #endif /* __riscos */
  16. #include "antiword.h"
  17.  
  18.  
  19. #define INITIAL_SIZE        40
  20. #define EXTENTION_SIZE        20
  21.  
  22.  
  23. /* Macros to make sure all such statements will be identical */
  24. #define OUTPUT_LINE()        \
  25.     do {\
  26.         vAlign2Window(pDiag, pAnchor, lWidthMax, ucAlignment);\
  27.         pAnchor = pStartNewOutput(pAnchor, NULL);\
  28.         pOutput = pAnchor;\
  29.     } while(0)
  30.  
  31. #define RESET_LINE()        \
  32.     do {\
  33.         pAnchor = pStartNewOutput(pAnchor, NULL);\
  34.         pOutput = pAnchor;\
  35.     } while(0)
  36.  
  37. #if defined(__riscos)
  38. /* Length of the document in characters */
  39. static long    lDocumentLength;
  40. /* Number of characters processed so far */
  41. static long    lCharCounter;
  42. static int    iCurrPct, iPrevPct;
  43. #endif /* __riscos */
  44. /* The document is in the format belonging to this version of Word */
  45. static int    iWordVersion = -1;
  46. /* Special treatment for files from Word 6 on an Apple Macintosh */
  47. static BOOL    bWord6MacFile = FALSE;
  48. /* All the (command line) options */
  49. static options_type    tOptions;
  50. /* Needed for reading a complete table row */
  51. static const row_block_type    *pRowInfo = NULL;
  52. static BOOL    bStartRow = FALSE;
  53. static BOOL    bEndRowNorm = FALSE;
  54. static BOOL    bEndRowFast = FALSE;
  55. static BOOL    bIsTableRow = FALSE;
  56. /* Needed for finding the start of a style */
  57. static const style_block_type    *pStyleInfo = NULL;
  58. static BOOL    bStartStyle = FALSE;
  59. /* Needed for finding the start of a font */
  60. static const font_block_type    *pFontInfo = NULL;
  61. static BOOL    bStartFont = FALSE;
  62. /* Needed for finding an image */
  63. static long    lFileOffsetImage = -1;
  64.  
  65.  
  66. /*
  67.  * vUpdateCounters - Update the counters for the hourglass
  68.  */
  69. static void
  70. vUpdateCounters(void)
  71. {
  72. #if defined(__riscos)
  73.     lCharCounter++;
  74.     iCurrPct = (int)((lCharCounter * 100) / lDocumentLength);
  75.     if (iCurrPct != iPrevPct) {
  76.         visdelay_percent(iCurrPct);
  77.         iPrevPct = iCurrPct;
  78.     }
  79. #endif /* __riscos */
  80. } /* end of vUpdateCounters */
  81.  
  82. /*
  83.  * bOutputContainsText - see if the output contains more than white space
  84.  */
  85. static BOOL
  86. bOutputContainsText(output_type *pAnchor)
  87. {
  88.     output_type    *pTmp;
  89.     int    iIndex;
  90.  
  91.     fail(pAnchor == NULL);
  92.  
  93.     for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
  94.         fail(pTmp->lStringWidth < 0);
  95.         for (iIndex = 0; iIndex < pTmp->iNextFree; iIndex++) {
  96.             if (isspace((int)pTmp->szStorage[iIndex])) {
  97.                 continue;
  98.             }
  99. #if defined(DEBUG)
  100.             if (pTmp->szStorage[iIndex] == FILLER_CHAR) {
  101.                 continue;
  102.             }
  103. #endif /* DEBUG */
  104.             return TRUE;
  105.         }
  106.     }
  107.     return FALSE;
  108. } /* end of bOutputContainsText */
  109.  
  110. /*
  111.  * lTotalStringWidth - compute the total width of the output string
  112.  */
  113. static long
  114. lTotalStringWidth(output_type *pAnchor)
  115. {
  116.     output_type    *pTmp;
  117.     long        lTotal;
  118.  
  119.     lTotal = 0;
  120.     for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
  121.         fail(pTmp->lStringWidth < 0);
  122.         lTotal += pTmp->lStringWidth;
  123.     }
  124.     return lTotal;
  125. } /* end of lTotalStringWidth */
  126.  
  127. /*
  128.  * vStoreByte - store one byte
  129.  */
  130. static void
  131. vStoreByte(unsigned char ucChar, output_type *pOutput)
  132. {
  133.     fail(pOutput == NULL);
  134.  
  135.     if (ucChar == 0) {
  136.         pOutput->szStorage[pOutput->iNextFree] = '\0';
  137.         return;
  138.     }
  139.     while (pOutput->iNextFree + 2 > (int)pOutput->tStorageSize) {
  140.         pOutput->tStorageSize += EXTENTION_SIZE;
  141.         pOutput->szStorage = xrealloc(pOutput->szStorage,
  142.                     pOutput->tStorageSize);
  143.     }
  144.     pOutput->szStorage[pOutput->iNextFree] = (char)ucChar;
  145.     pOutput->szStorage[pOutput->iNextFree + 1] = '\0';
  146.     pOutput->iNextFree++;
  147. } /* end of vStoreByte */
  148.  
  149. /*
  150.  * vStoreCharacter - store one character
  151.  */
  152. static void
  153. vStoreCharacter(unsigned long ulChar, output_type *pOutput)
  154. {
  155.     int    iLen;
  156.  
  157.     fail(pOutput == NULL);
  158.  
  159.     if (tOptions.eEncoding == encoding_utf8) {
  160.         fail(ulChar > 0xffff);
  161.         if (ulChar < 0x80) {
  162.             vStoreByte((unsigned char)ulChar, pOutput);
  163.             iLen = 1;
  164.         } else if (ulChar < 0x800) {
  165.             vStoreByte((unsigned char)(0xc0 | ulChar >> 6),
  166.                                 pOutput);
  167.             vStoreByte((unsigned char)(0x80 | (ulChar & 0x3f)),
  168.                                 pOutput);
  169.             iLen = 2;
  170.         } else {
  171.             vStoreByte((unsigned char)(0xe0 | ulChar >> 12),
  172.                                 pOutput);
  173.             vStoreByte((unsigned char)(0x80 | (ulChar >> 6 & 0x3f)),
  174.                                 pOutput);
  175.             vStoreByte((unsigned char)(0x80 | (ulChar & 0x3f)),
  176.                                 pOutput);
  177.             iLen = 3;
  178.         }
  179.     } else {
  180.         fail(ulChar > 0xff);
  181.         vStoreByte((unsigned char)ulChar, pOutput);
  182.         iLen = 1;
  183.     }
  184.     pOutput->lStringWidth += lComputeStringWidth(
  185.                 pOutput->szStorage + pOutput->iNextFree - iLen,
  186.                 iLen,
  187.                 pOutput->tFontRef,
  188.                 pOutput->sFontsize);
  189. } /* end of vStoreCharacter */
  190.  
  191. /*
  192.  * vStoreString - store a string
  193.  */
  194. static void
  195. vStoreString(const char *szString, int iStringLength, output_type *pOutput)
  196. {
  197.     int    iIndex;
  198.  
  199.     fail(szString == NULL || iStringLength < 0 || pOutput == NULL);
  200.  
  201.     for (iIndex = 0; iIndex < iStringLength; iIndex++) {
  202.         vStoreCharacter(szString[iIndex], pOutput);
  203.     }
  204. } /* end of vStoreString */
  205.  
  206. /*
  207.  * vStoreIntegerAsDecimal - store an integer as a decimal number
  208.  */
  209. static void
  210. vStoreIntegerAsDecimal(int iNumber, output_type *pOutput)
  211. {
  212.     int    iLen;
  213.     char    szString[15];
  214.  
  215.     fail(pOutput == NULL);
  216.  
  217.     iLen = sprintf(szString, "%d", iNumber);
  218.     vStoreString(szString, iLen, pOutput);
  219. } /* end of vStoreIntegerAsDecimal */
  220.  
  221. /*
  222.  * vStoreIntegerAsRoman - store an integer as a roman numerical
  223.  */
  224. static void
  225. vStoreIntegerAsRoman(int iNumber, output_type *pOutput)
  226. {
  227.     int    iLen;
  228.     char    szString[15];
  229.  
  230.     fail(iNumber <= 0);
  231.     fail(pOutput == NULL);
  232.  
  233.     iLen = iInteger2Roman(iNumber, FALSE, szString);
  234.     vStoreString(szString, iLen, pOutput);
  235. } /* end of vStoreIntegerAsRoman */
  236.  
  237. /*
  238.  * vStoreStyle - store a style
  239.  */
  240. static void
  241. vStoreStyle(output_type *pOutput)
  242. {
  243.     int    iLen;
  244.     char    szString[120];
  245.  
  246.     fail(pOutput == NULL);
  247.     iLen = iStyle2Window(szString, pStyleInfo);
  248.     vStoreString(szString, iLen, pOutput);
  249. } /* end of vStoreStyle */
  250.  
  251. /*
  252.  * Create an empty line by adding a extra "newline"
  253.  */
  254. static void
  255. vEmptyLine2Diagram(diagram_type *pDiag, draw_fontref tFontRef, int iFontsize)
  256. {
  257.     fail(pDiag == NULL);
  258.     fail(iFontsize < MIN_FONT_SIZE || iFontsize > MAX_FONT_SIZE);
  259.  
  260.     if (pDiag->lXleft > 0) {
  261.         /* To the start of the line */
  262.         vMove2NextLine(pDiag, tFontRef, iFontsize);
  263.     }
  264.     /* Empty line */
  265.     vMove2NextLine(pDiag, tFontRef, iFontsize);
  266. } /* end of vEmptyLine2Diagram */
  267.  
  268. /*
  269.  * vPutIndentation - output the given amount of indentation
  270.  */
  271. static void
  272. vPutIndentation(diagram_type *pDiag, output_type *pOutput, BOOL bUnmarked,
  273.     int iListNumber, unsigned char ucListType, char cListCharacter,
  274.     int iLeftIndent)
  275. {
  276.     long    lWidth, lLeftIndentation;
  277.     int    iNextFree;
  278.     char    szLine[30];
  279.  
  280.     fail(pDiag == NULL || pOutput == NULL);
  281.     fail(iListNumber < 0);
  282.     fail(iLeftIndent < 0);
  283.  
  284.     if (iLeftIndent <= 0) {
  285.         return;
  286.     }
  287.     lLeftIndentation = lTwips2MilliPoints(iLeftIndent);
  288.     if (bUnmarked) {
  289.         vSetLeftIndentation(pDiag, lLeftIndentation);
  290.         return;
  291.     }
  292.     fail(iListNumber <= 0);
  293.     fail(iscntrl((int)cListCharacter));
  294.  
  295.     switch (ucListType) {
  296.     case LIST_ARABIC_NUM:
  297.         iNextFree = sprintf(szLine, "%d", iListNumber);
  298.         break;
  299.     case LIST_ROMAN_NUM_UPPER:
  300.     case LIST_ROMAN_NUM_LOWER:
  301.         iNextFree = iInteger2Roman(iListNumber,
  302.             ucListType == LIST_ROMAN_NUM_UPPER, szLine);
  303.         break;
  304.     case LIST_UPPER_ALPHA:
  305.     case LIST_LOWER_ALPHA:
  306.         iNextFree = iInteger2Alpha(iListNumber,
  307.             ucListType == LIST_UPPER_ALPHA, szLine);
  308.         break;
  309.     case LIST_ORDINAL_NUM:
  310.         if (iListNumber % 10 == 1 && iListNumber != 11) {
  311.             iNextFree = sprintf(szLine, "%dst", iListNumber);
  312.         } else if (iListNumber % 10 == 2 && iListNumber != 12) {
  313.             iNextFree = sprintf(szLine, "%dnd", iListNumber);
  314.         } else if (iListNumber % 10 == 3 && iListNumber != 13) {
  315.             iNextFree = sprintf(szLine, "%drd", iListNumber);
  316.         } else {
  317.             iNextFree = sprintf(szLine, "%dth", iListNumber);
  318.         }
  319.         break;
  320.     case LIST_BULLETS:
  321.         iNextFree = 0;
  322.         break;
  323.     default:
  324.         DBG_DEC(ucListType);
  325.         DBG_FIXME();
  326.         iNextFree = sprintf(szLine, "%d", iListNumber);
  327.         break;
  328.     }
  329.     szLine[iNextFree++] = cListCharacter;
  330.     szLine[iNextFree++] = ' ';
  331.     szLine[iNextFree] = '\0';
  332.     lWidth = lComputeStringWidth(szLine, iNextFree,
  333.                 pOutput->tFontRef, pOutput->sFontsize);
  334.     lLeftIndentation -= lWidth;
  335.     if (lLeftIndentation > 0) {
  336.         vSetLeftIndentation(pDiag, lLeftIndentation);
  337.     }
  338.     vStoreString(szLine, iNextFree, pOutput);
  339. } /* end of vPutIndentation */
  340.  
  341. /*
  342.  * vPutNoteSeparator - output a note separator
  343.  *
  344.  * A note separator is a horizontal line two inches long.
  345.  * Two inches equals 144000 millipoints.
  346.  */
  347. static void
  348. vPutNoteSeparator(output_type *pOutput)
  349. {
  350.     long    lCharWidth;
  351.     int    iCounter, iChars;
  352.     char    szOne[2];
  353.  
  354.     fail(pOutput == NULL);
  355.  
  356.     szOne[0] = OUR_EM_DASH;
  357.     szOne[1] = '\0';
  358.     lCharWidth = lComputeStringWidth(szOne, 1,
  359.                 pOutput->tFontRef, pOutput->sFontsize);
  360.     DBG_DEC(lCharWidth);
  361.     iChars = (int)((144000 + lCharWidth / 2) / lCharWidth);
  362.     DBG_DEC(iChars);
  363.     for (iCounter = 0; iCounter < iChars; iCounter++) {
  364.         vStoreCharacter(OUR_EM_DASH, pOutput);
  365.     }
  366. } /* end of vPutNoteSeparator */
  367.  
  368. /*
  369.  *
  370.  */
  371. static output_type *
  372. pStartNextOutput(output_type *pCurrent)
  373. {
  374.     output_type    *pNew;
  375.  
  376.     if (pCurrent->iNextFree == 0) {
  377.         /* The current record is empty, re-use */
  378.         fail(pCurrent->szStorage[0] != '\0');
  379.         fail(pCurrent->lStringWidth != 0);
  380.         return pCurrent;
  381.     }
  382.     /* The current record is in use, make a new one */
  383.     pNew = xmalloc(sizeof(*pNew));
  384.     pCurrent->pNext = pNew;
  385.     pNew->tStorageSize = INITIAL_SIZE;
  386.     pNew->szStorage = xmalloc(pNew->tStorageSize);
  387.     pNew->szStorage[0] = '\0';
  388.     pNew->iNextFree = 0;
  389.     pNew->lStringWidth = 0;
  390.     pNew->iColor = FONT_COLOR_DEFAULT;
  391.     pNew->ucFontstyle = FONT_REGULAR;
  392.     pNew->tFontRef = (draw_fontref)0;
  393.     pNew->sFontsize = DEFAULT_FONT_SIZE;
  394.     pNew->pPrev = pCurrent;
  395.     pNew->pNext = NULL;
  396.     return pNew;
  397. } /* end of pStartNextOutput */
  398.  
  399. /*
  400.  * pStartNewOutput
  401.  */
  402. static output_type *
  403. pStartNewOutput(output_type *pAnchor, output_type *pLeftOver)
  404. {
  405.     output_type    *pCurr, *pNext;
  406.     int        iColor;
  407.     short        sFontsize;
  408.     draw_fontref    tFontRef;
  409.     unsigned char    ucFontstyle;
  410.  
  411.     iColor = FONT_COLOR_DEFAULT;
  412.     ucFontstyle = FONT_REGULAR;
  413.     tFontRef = (draw_fontref)0;
  414.     sFontsize = DEFAULT_FONT_SIZE;
  415.     /* Free the old output space */
  416.     pCurr = pAnchor;
  417.     while (pCurr != NULL) {
  418.         pNext = pCurr->pNext;
  419.         pCurr->szStorage = xfree(pCurr->szStorage);
  420.         if (pCurr->pNext == NULL) {
  421.             iColor = pCurr->iColor;
  422.             ucFontstyle = pCurr->ucFontstyle;
  423.             tFontRef = pCurr->tFontRef;
  424.             sFontsize = pCurr->sFontsize;
  425.         }
  426.         pCurr = xfree(pCurr);
  427.         pCurr = pNext;
  428.     }
  429.     if (pLeftOver == NULL) {
  430.         /* Create new output space */
  431.         pLeftOver = xmalloc(sizeof(*pLeftOver));
  432.         pLeftOver->tStorageSize = INITIAL_SIZE;
  433.         pLeftOver->szStorage = xmalloc(pLeftOver->tStorageSize);
  434.         pLeftOver->szStorage[0] = '\0';
  435.         pLeftOver->iNextFree = 0;
  436.         pLeftOver->lStringWidth = 0;
  437.         pLeftOver->iColor = iColor;
  438.         pLeftOver->ucFontstyle = ucFontstyle;
  439.         pLeftOver->tFontRef = tFontRef;
  440.         pLeftOver->sFontsize = sFontsize;
  441.         pLeftOver->pPrev = NULL;
  442.         pLeftOver->pNext = NULL;
  443.     }
  444.     fail(!bCheckDoubleLinkedList(pLeftOver));
  445.     return pLeftOver;
  446. } /* end of pStartNewOutput */
  447.  
  448. /*
  449.  * ulGetChar - get the next character from the given list
  450.  *
  451.  * returns the next character of EOF
  452.  */
  453. static unsigned long
  454. ulGetChar(FILE *pFile, list_id_enum eListID)
  455. {
  456.     const font_block_type    *pCurr;
  457.     unsigned long        ulChar;
  458.     long        lFileOffset, lTextOffset;
  459.     row_info_enum    eRowInfo;
  460.     unsigned short    usChar, usPropMod;
  461.     BOOL    bSkip;
  462.  
  463.     fail(pFile == NULL);
  464.  
  465.     pCurr = pFontInfo;
  466.     bSkip = FALSE;
  467.     for (;;) {
  468.         usChar = usNextChar(pFile, eListID,
  469.                     &lFileOffset, &lTextOffset, &usPropMod);
  470.         if (usChar == (unsigned short)EOF) {
  471.             return (unsigned long)EOF;
  472.         }
  473.  
  474.         vUpdateCounters();
  475.  
  476.         eRowInfo = ePropMod2RowInfo(usPropMod, iWordVersion);
  477.         if (!bStartRow) {
  478. #if 0
  479.             bStartRow = eRowInfo == found_a_cell ||
  480.                 (pRowInfo != NULL &&
  481.                  lFileOffset == pRowInfo->lFileOffsetStart &&
  482.                  eRowInfo != found_not_a_cell);
  483. #else
  484.             bStartRow = pRowInfo != NULL &&
  485.                 lFileOffset == pRowInfo->lFileOffsetStart;
  486. #endif
  487.             NO_DBG_HEX_C(bStartRow, pRowInfo->lFileOffsetStart);
  488.         }
  489.         if (!bEndRowNorm) {
  490. #if 0
  491.             bEndRow = eRowInfo == found_end_of_row ||
  492.                 (pRowInfo != NULL &&
  493.                  lFileOffset == pRowInfo->lFileOffsetEnd &&
  494.                  eRowInfo != found_not_end_of_row);
  495. #else
  496.             bEndRowNorm = pRowInfo != NULL &&
  497.                 lFileOffset == pRowInfo->lFileOffsetEnd;
  498. #endif
  499.             NO_DBG_HEX_C(bEndRowNorm, pRowInfo->lFileOffsetEnd);
  500.         }
  501.         if (!bEndRowFast) {
  502.             bEndRowFast = eRowInfo == found_end_of_row;
  503.             NO_DBG_HEX_C(bEndRowFast, pRowInfo->lFileOffsetEnd);
  504.         }
  505.  
  506.         if (!bStartStyle) {
  507.             bStartStyle = pStyleInfo != NULL &&
  508.                 lFileOffset == pStyleInfo->lFileOffset;
  509.             NO_DBG_HEX_C(bStartStyle, lFileOffset);
  510.         }
  511.         if (pCurr != NULL && lFileOffset == pCurr->lFileOffset) {
  512.             bStartFont = TRUE;
  513.             NO_DBG_HEX(lFileOffset);
  514.             pFontInfo = pCurr;
  515.             pCurr = pGetNextFontInfoListItem(pCurr);
  516.         }
  517.  
  518.         /* Skip embedded characters */
  519.         if (usChar == START_EMBEDDED) {
  520.             bSkip = TRUE;
  521.             continue;
  522.         }
  523.         if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
  524.             bSkip = FALSE;
  525.             continue;
  526.         }
  527.         if (bSkip) {
  528.             continue;
  529.         }
  530.         ulChar = ulTranslateCharacters(usChar,
  531.                     lFileOffset,
  532.                     tOptions.eEncoding == encoding_utf8,
  533.                     bWord6MacFile);
  534.         if (ulChar == IGNORE_CHARACTER) {
  535.             continue;
  536.         }
  537.         if (ulChar == PICTURE) {
  538.             lFileOffsetImage = lGetPicInfoListItem(lFileOffset);
  539.         } else {
  540.             lFileOffsetImage = -1;
  541.         }
  542.         return ulChar;
  543.     }
  544. } /* end of ulGetChar */
  545.  
  546. /*
  547.  * vWord2Text
  548.  */
  549. void
  550. vWord2Text(FILE *pFile, long lFilesize, diagram_type *pDiag)
  551. {
  552.     imagedata_type    tImage;
  553.     output_type    *pAnchor, *pOutput, *pLeftOver;
  554.     unsigned long    ulChar;
  555.     long    lWidthCurr, lWidthMax, lRightIndentation;
  556.     long    lDefaultTabWidth, lTmp;
  557.     list_id_enum     eListID;
  558.     image_info_enum    eRes;
  559.     int    iFootnoteNumber, iEndnoteNumber, iLeftIndent;
  560.     int    iListNumber;
  561.     BOOL    bWasTableRow, bTableFontClosed, bUnmarked;
  562.     BOOL    bAllCapitals, bHiddenText, bSuccess;
  563.     short    sFontsize;
  564.     unsigned char    ucFontnumber, ucFontcolor, ucTmp;
  565.     unsigned char    ucFontstyle, ucFontstyleMinimal;
  566.     unsigned char    ucListType, ucAlignment;
  567.     char    cListChar;
  568.  
  569.     fail(pFile == NULL || lFilesize <= 0 || pDiag == NULL);
  570.  
  571.     DBG_MSG("vWord2Text");
  572.  
  573.     iWordVersion = iInitDocument(pFile, lFilesize);
  574.     if (iWordVersion < 6) {
  575.         return;
  576.     }
  577.     vAddFonts2Diagram(pDiag);
  578.  
  579.     /* Initialisation */
  580. #if defined(__riscos)
  581.     lCharCounter = 0;
  582.     iCurrPct = 0;
  583.     iPrevPct = -1;
  584.     lDocumentLength = lGetDocumentLength();
  585. #endif /* __riscos */
  586.     bWord6MacFile = bIsWord6MacFile();
  587.     lDefaultTabWidth = lGetDefaultTabWidth();
  588.     DBG_DEC_C(lDefaultTabWidth != 36000, lDefaultTabWidth);
  589.     pRowInfo = pGetNextRowInfoListItem();
  590.     DBG_HEX_C(pRowInfo != NULL, pRowInfo->lFileOffsetStart);
  591.     DBG_HEX_C(pRowInfo != NULL, pRowInfo->lFileOffsetEnd);
  592.     DBG_MSG_C(pRowInfo == NULL, "No rows at all");
  593.     bStartRow = FALSE;
  594.     bEndRowNorm = FALSE;
  595.     bEndRowFast = FALSE;
  596.     bIsTableRow = FALSE;
  597.     bWasTableRow = FALSE;
  598.     vResetStyles();
  599.     pStyleInfo = pGetNextStyleInfoListItem();
  600.     bStartStyle = FALSE;
  601.     pAnchor = NULL;
  602.     pFontInfo = pGetNextFontInfoListItem(NULL);
  603.     DBG_HEX_C(pFontInfo != NULL, pFontInfo->lFileOffset);
  604.     DBG_MSG_C(pFontInfo == NULL, "No fonts at all");
  605.     bStartFont = FALSE;
  606.     ucFontnumber = 0;
  607.     ucFontstyleMinimal = FONT_REGULAR;
  608.     ucFontstyle = FONT_REGULAR;
  609.     sFontsize = DEFAULT_FONT_SIZE;
  610.     ucFontcolor = FONT_COLOR_DEFAULT;
  611.     pAnchor = pStartNewOutput(pAnchor, NULL);
  612.     pOutput = pAnchor;
  613.     pOutput->iColor = ucFontcolor;
  614.     pOutput->ucFontstyle = ucFontstyle;
  615.     pOutput->tFontRef = tOpenFont(ucFontnumber, ucFontstyle, sFontsize);
  616.     pOutput->sFontsize = sFontsize;
  617.     bTableFontClosed = TRUE;
  618.     iLeftIndent = 0;
  619.     lRightIndentation = 0;
  620.     bUnmarked = TRUE;
  621.     ucListType = LIST_BULLETS;
  622.     cListChar = OUR_BULLET;
  623.     iListNumber = 0;
  624.     ucAlignment = ALIGNMENT_LEFT;
  625.     bAllCapitals = FALSE;
  626.     bHiddenText = FALSE;
  627.     vGetOptions(&tOptions);
  628.     fail(tOptions.iParagraphBreak < 0);
  629.     if (tOptions.iParagraphBreak == 0) {
  630.         lWidthMax = LONG_MAX;
  631.     } else if (tOptions.iParagraphBreak < MIN_SCREEN_WIDTH) {
  632.         lWidthMax = lChar2MilliPoints(MIN_SCREEN_WIDTH);
  633.     } else if (tOptions.iParagraphBreak > MAX_SCREEN_WIDTH) {
  634.         lWidthMax = lChar2MilliPoints(MAX_SCREEN_WIDTH);
  635.     } else {
  636.         lWidthMax = lChar2MilliPoints(tOptions.iParagraphBreak);
  637.     }
  638.     NO_DBG_DEC(lWidthMax);
  639.  
  640.     visdelay_begin();
  641.  
  642.     iFootnoteNumber = 0;
  643.     iEndnoteNumber = 0;
  644.     eListID = text_list;
  645.     for(;;) {
  646.         ulChar = ulGetChar(pFile, eListID);
  647.         if (ulChar == (unsigned long)EOF) {
  648.             if (bOutputContainsText(pAnchor)) {
  649.                 OUTPUT_LINE();
  650.             } else {
  651.                 RESET_LINE();
  652.             }
  653.             switch (eListID) {
  654.             case text_list:
  655.                 eListID = footnote_list;
  656.                 if (iFootnoteNumber > 0) {
  657.                     vPutNoteSeparator(pAnchor);
  658.                     OUTPUT_LINE();
  659.                     iFootnoteNumber = 0;
  660.                 }
  661.                 break;
  662.             case footnote_list:
  663.                 eListID = endnote_list;
  664.                 if (iEndnoteNumber > 0) {
  665.                     vPutNoteSeparator(pAnchor);
  666.                     OUTPUT_LINE();
  667.                     iEndnoteNumber = 0;
  668.                 }
  669.                 break;
  670.             case endnote_list:
  671.             default:
  672.                 eListID = end_of_lists;
  673.                 break;
  674.             }
  675.             if (eListID == end_of_lists) {
  676.                 break;
  677.             }
  678.             continue;
  679.         }
  680.  
  681.         if (ulChar == UNKNOWN_NOTE_CHAR) {
  682.             switch (eListID) {
  683.             case footnote_list:
  684.                 ulChar = FOOTNOTE_CHAR;
  685.                 break;
  686.             case endnote_list:
  687.                 ulChar = ENDNOTE_CHAR;
  688.                 break;
  689.             default:
  690.                 break;
  691.             }
  692.         }
  693.  
  694.         if (bStartRow) {
  695.             /* Begin of a tablerow found */
  696.             if (bOutputContainsText(pAnchor)) {
  697.                 OUTPUT_LINE();
  698.             } else {
  699.                 RESET_LINE();
  700.             }
  701.             fail(pAnchor != pOutput);
  702.             if (bTableFontClosed) {
  703.                 /* Start special table font */
  704.                 vCloseFont();
  705.                 /*
  706.                  * Compensate for the fact that Word uses
  707.                  * proportional fonts for its tables and we
  708.                  * only one fixed-width font
  709.                  */
  710.                 pOutput->sFontsize =
  711.                     (sFontsize <= DEFAULT_FONT_SIZE ?
  712.                      (DEFAULT_FONT_SIZE * 5 + 3) / 6 :
  713.                      (sFontsize * 5 + 3) / 6);
  714.                 pOutput->tFontRef =
  715.                     tOpenTableFont(pOutput->sFontsize);
  716.                 pOutput->ucFontstyle = FONT_REGULAR;
  717.                 pOutput->iColor = FONT_COLOR_BLACK;
  718.                 bTableFontClosed = FALSE;
  719.             }
  720.             bIsTableRow = TRUE;
  721.             bStartRow = FALSE;
  722.         }
  723.  
  724.         if (bWasTableRow &&
  725.             !bIsTableRow &&
  726.             ulChar != PAR_END &&
  727.             ulChar != HARD_RETURN &&
  728.             ulChar != FORM_FEED &&
  729.             ulChar != COLUMN_FEED) {
  730.             /*
  731.              * The end of a table should be followed by an
  732.              * empty line, like the end of a paragraph
  733.              */
  734.             OUTPUT_LINE();
  735.             vEndOfParagraph2Diagram(pDiag,
  736.                         pOutput->tFontRef,
  737.                         pOutput->sFontsize);
  738.         }
  739.  
  740.         switch (ulChar) {
  741.         case FORM_FEED:
  742.         case COLUMN_FEED:
  743.             if (bIsTableRow) {
  744.                 vStoreCharacter('\n', pOutput);
  745.                 break;
  746.             }
  747.             if (bOutputContainsText(pAnchor)) {
  748.                 OUTPUT_LINE();
  749.             } else {
  750.                 RESET_LINE();
  751.             }
  752.             if (ulChar == FORM_FEED) {
  753.                 vEndOfPage2Diagram(pDiag,
  754.                         pOutput->tFontRef,
  755.                         pOutput->sFontsize);
  756.             } else {
  757.                 vEndOfParagraph2Diagram(pDiag,
  758.                         pOutput->tFontRef,
  759.                         pOutput->sFontsize);
  760.             }
  761.             break;
  762.         default:
  763.             break;
  764.         }
  765.  
  766.         if (bStartFont) {
  767.             /* Begin of a font found */
  768.             fail(pFontInfo == NULL);
  769.             bAllCapitals = bIsCapitals(pFontInfo->ucFontstyle);
  770.             bHiddenText = bIsHidden(pFontInfo->ucFontstyle);
  771.             ucTmp = pFontInfo->ucFontstyle &
  772.             (FONT_BOLD|FONT_ITALIC|FONT_UNDERLINE|FONT_STRIKE);
  773.             if (!bIsTableRow &&
  774.                 (sFontsize != pFontInfo->sFontsize ||
  775.                 ucFontnumber != pFontInfo->ucFontnumber ||
  776.                 ucFontstyleMinimal != ucTmp ||
  777.                 ucFontcolor != pFontInfo->ucFontcolor)) {
  778.                 pOutput = pStartNextOutput(pOutput);
  779.                 vCloseFont();
  780.                 pOutput->iColor = pFontInfo->ucFontcolor;
  781.                 pOutput->ucFontstyle = pFontInfo->ucFontstyle;
  782.                 pOutput->sFontsize = pFontInfo->sFontsize;
  783.                 pOutput->tFontRef = tOpenFont(
  784.                         pFontInfo->ucFontnumber,
  785.                         pFontInfo->ucFontstyle,
  786.                         pFontInfo->sFontsize);
  787.                 fail(!bCheckDoubleLinkedList(pAnchor));
  788.             }
  789.             ucFontnumber = pFontInfo->ucFontnumber;
  790.             sFontsize = pFontInfo->sFontsize;
  791.             ucFontcolor = pFontInfo->ucFontcolor;
  792.             ucFontstyle = pFontInfo->ucFontstyle;
  793.             ucFontstyleMinimal = ucTmp;
  794.             pFontInfo = pGetNextFontInfoListItem(pFontInfo);
  795.             NO_DBG_HEX_C(pFontInfo != NULL, pFontInfo->lFileOffset);
  796.             DBG_MSG_C(pFontInfo == NULL, "No more fonts");
  797.             bStartFont = FALSE;
  798.         }
  799.  
  800.         if (bStartStyle) {
  801.             /* Begin of a style found */
  802.             fail(pStyleInfo == NULL);
  803.             if (!bIsTableRow) {
  804.                 vStoreStyle(pOutput);
  805.             }
  806.             iLeftIndent = pStyleInfo->sLeftIndent;
  807.             lRightIndentation =
  808.                 lTwips2MilliPoints(pStyleInfo->sRightIndent);
  809.             bUnmarked = !pStyleInfo->bInList ||
  810.                         pStyleInfo->bUnmarked;
  811.             ucListType = pStyleInfo->ucListType;
  812.             cListChar = (char)pStyleInfo->ucListCharacter;
  813.             ucAlignment = pStyleInfo->ucAlignment;
  814.             if (pStyleInfo->bInList) {
  815.                 if (!pStyleInfo->bUnmarked) {
  816.                     iListNumber++;
  817.                 }
  818.             } else {
  819.                 iListNumber = 0;
  820.             }
  821.             pStyleInfo = pGetNextStyleInfoListItem();
  822.             NO_DBG_HEX_C(pStyleInfo != NULL,
  823.                         pStyleInfo->lFileOffset);
  824.             bStartStyle = FALSE;
  825.         }
  826.  
  827.         if (!bIsTableRow &&
  828.             lTotalStringWidth(pAnchor) == 0) {
  829.             vPutIndentation(pDiag, pAnchor, bUnmarked,
  830.                     iListNumber, ucListType, cListChar,
  831.                     iLeftIndent);
  832.             /* One mark per paragraph will do */
  833.             bUnmarked = TRUE;
  834.         }
  835.  
  836.         switch (ulChar) {
  837.         case PICTURE:
  838.             (void)memset(&tImage, 0, sizeof(tImage));
  839.             eRes = eExamineImage(pFile, lFileOffsetImage, &tImage);
  840.             switch (eRes) {
  841.             case image_no_information:
  842.                 bSuccess = FALSE;
  843.                 break;
  844.             case image_minimal_information:
  845.             case image_full_information:
  846. #if 0
  847.                 if (bOutputContainsText(pAnchor)) {
  848.                     OUTPUT_LINE();
  849.                 } else {
  850.                     RESET_LINE();
  851.                 }
  852. #endif
  853.                 bSuccess = bTranslateImage(pDiag, pFile,
  854.                     eRes == image_minimal_information,
  855.                     lFileOffsetImage, &tImage);
  856.                 break;
  857.             default:
  858.                 DBG_DEC(eRes);
  859.                 bSuccess = FALSE;
  860.                 break;
  861.             }
  862.             if (!bSuccess) {
  863.                 vStoreString("[pic]", 5, pOutput);
  864.             }
  865.             break;
  866.         case FOOTNOTE_CHAR:
  867.             iFootnoteNumber++;
  868.             vStoreCharacter('[', pOutput);
  869.             vStoreIntegerAsDecimal(iFootnoteNumber, pOutput);
  870.             vStoreCharacter(']', pOutput);
  871.             break;
  872.         case ENDNOTE_CHAR:
  873.             iEndnoteNumber++;
  874.             vStoreCharacter('[', pOutput);
  875.             vStoreIntegerAsRoman(iEndnoteNumber, pOutput);
  876.             vStoreCharacter(']', pOutput);
  877.             break;
  878.         case UNKNOWN_NOTE_CHAR:
  879.             vStoreString("[?]", 3, pOutput);
  880.             break;
  881.         case PAR_END:
  882.             if (bIsTableRow) {
  883.                 vStoreCharacter('\n', pOutput);
  884.                 break;
  885.             }
  886.             if (bOutputContainsText(pAnchor)) {
  887.                 OUTPUT_LINE();
  888.             } else {
  889.                 RESET_LINE();
  890.             }
  891.             vEndOfParagraph2Diagram(pDiag,
  892.                         pOutput->tFontRef,
  893.                         pOutput->sFontsize);
  894.             /*
  895.              * End of paragraph seen, reset indentation,
  896.              * marking and alignment
  897.              */
  898.             iLeftIndent = 0;
  899.             lRightIndentation = 0;
  900.             bUnmarked = TRUE;
  901.             ucAlignment = ALIGNMENT_LEFT;
  902.             break;
  903.         case HARD_RETURN:
  904.             if (bIsTableRow) {
  905.                 vStoreCharacter('\n', pOutput);
  906.                 break;
  907.             }
  908.             if (bOutputContainsText(pAnchor)) {
  909.                 OUTPUT_LINE();
  910.             }
  911.             vEmptyLine2Diagram(pDiag,
  912.                     pOutput->tFontRef,
  913.                     pOutput->sFontsize);
  914.             break;
  915.         case FORM_FEED:
  916.         case COLUMN_FEED:
  917.             /* Already dealt with */
  918.             break;
  919.         case TABLE_SEPARATOR:
  920.             if (bIsTableRow) {
  921.                 vStoreCharacter(ulChar, pOutput);
  922.                 break;
  923.             }
  924.             vStoreCharacter(' ', pOutput);
  925.             vStoreCharacter(TABLE_SEPARATOR_CHAR, pOutput);
  926.             break;
  927.         case TAB:
  928.             if (bIsTableRow) {
  929.                 vStoreCharacter(' ', pOutput);
  930.                 break;
  931.             }
  932.             if (tOptions.iParagraphBreak == 0 &&
  933.                 !tOptions.bUseOutlineFonts) {
  934.                 /* No logical lines, so no tab expansion */
  935.                 vStoreCharacter(TAB, pOutput);
  936.                 break;
  937.             }
  938.             lTmp = lTotalStringWidth(pAnchor);
  939.             lTmp += lDrawUnits2MilliPoints(pDiag->lXleft);
  940.             lTmp /= lDefaultTabWidth;
  941.             do {
  942.                 vStoreCharacter(FILLER_CHAR, pOutput);
  943.                 lWidthCurr = lTotalStringWidth(pAnchor);
  944.                 lWidthCurr +=
  945.                     lDrawUnits2MilliPoints(pDiag->lXleft);
  946.             } while (lTmp == lWidthCurr / lDefaultTabWidth &&
  947.                  lWidthCurr < lWidthMax + lRightIndentation);
  948.             break;
  949.         default:
  950.             if (bHiddenText && tOptions.bHideHiddenText) {
  951.                 continue;
  952.             }
  953.             if (bAllCapitals) {
  954.                 ulChar = ulToUpper(ulChar);
  955.             }
  956.             vStoreCharacter(ulChar, pOutput);
  957.             break;
  958.         }
  959.  
  960.         if (bWasTableRow && !bIsTableRow) {
  961.             /* End of a table, resume normal font */
  962.             NO_DBG_MSG("End of table font");
  963.             vCloseFont();
  964.             bTableFontClosed = TRUE;
  965.             pOutput->iColor = ucFontcolor;
  966.             pOutput->ucFontstyle = ucFontstyle;
  967.             pOutput->sFontsize = sFontsize;
  968.             pOutput->tFontRef =
  969.                 tOpenFont(ucFontnumber, ucFontstyle, sFontsize);
  970.         }
  971.         bWasTableRow = bIsTableRow;
  972.  
  973.         if (bIsTableRow) {
  974.             fail(pAnchor != pOutput);
  975.             if (!bEndRowNorm && !bEndRowFast) {
  976.                 continue;
  977.             }
  978.             /* End of a table row */
  979.             if (bEndRowNorm) {
  980.                 fail(pRowInfo == NULL);
  981.                 vTableRow2Window(pDiag, pAnchor, pRowInfo);
  982.             } else {
  983.                 fail(!bEndRowFast);
  984.             }
  985.             /* Reset */
  986.             pAnchor = pStartNewOutput(pAnchor, NULL);
  987.             pOutput = pAnchor;
  988.             if (bEndRowNorm) {
  989.                 pRowInfo = pGetNextRowInfoListItem();
  990.             }
  991.             bIsTableRow = FALSE;
  992.             bEndRowNorm = FALSE;
  993.             bEndRowFast = FALSE;
  994.             DBG_HEX_C(pRowInfo != NULL, pRowInfo->lFileOffsetStart);
  995.             DBG_HEX_C(pRowInfo != NULL, pRowInfo->lFileOffsetEnd);
  996.             continue;
  997.         }
  998.         lWidthCurr = lTotalStringWidth(pAnchor);
  999.         lWidthCurr += lDrawUnits2MilliPoints(pDiag->lXleft);
  1000.         if (lWidthCurr < lWidthMax + lRightIndentation) {
  1001.             continue;
  1002.         }
  1003.         pLeftOver = pSplitList(pAnchor);
  1004.         vJustify2Window(pDiag, pAnchor,
  1005.                 lWidthMax, lRightIndentation, ucAlignment);
  1006.         pAnchor = pStartNewOutput(pAnchor, pLeftOver);
  1007.         for (pOutput = pAnchor;
  1008.              pOutput->pNext != NULL;
  1009.              pOutput = pOutput->pNext)
  1010.             ;    /* EMPTY */
  1011.         fail(pOutput == NULL);
  1012.         if (lTotalStringWidth(pAnchor) > 0) {
  1013.             vSetLeftIndentation(pDiag,
  1014.                     lTwips2MilliPoints(iLeftIndent));
  1015.         }
  1016.     }
  1017.  
  1018.     pAnchor = pStartNewOutput(pAnchor, NULL);
  1019.     pAnchor->szStorage = xfree(pAnchor->szStorage);
  1020.     pAnchor = xfree(pAnchor);
  1021.     vCloseFont();
  1022.     vFreeDocument();
  1023.     visdelay_end();
  1024. } /* end of vWord2Text */
  1025.