Imported from antiword-0.30.tar.gz.
[antiword.git] / word2text.c
blobede17ed4103ab17915f5b09d28a74e659f30685d
1 /*
2 * word2text.c
3 * Copyright (C) 1998,1999 A.J. van Os
5 * Description:
6 * MS Word to text functions
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <limits.h>
14 #if defined(__riscos)
15 #include "visdelay.h"
16 #endif /* __riscos */
17 #include "antiword.h"
20 #define INITIAL_SIZE 40
21 #define EXTENTION_SIZE 20
24 /* Macros to make sure all such statements will be identical */
25 #define OUTPUT_LINE() \
26 do {\
27 vAlign2Window(pDiag, pAnchor, iWidthMax, ucAlignment);\
28 pAnchor = pStartNewOutput(pAnchor, NULL);\
29 pOutput = pAnchor;\
30 } while(0)
32 #define RESET_LINE() \
33 do {\
34 pAnchor = pStartNewOutput(pAnchor, NULL);\
35 pOutput = pAnchor;\
36 } while(0)
38 /* Length of the document in characters */
39 static unsigned int uiDocumentLength;
40 /* Number of characters processed so far */
41 static unsigned int uiCharCounter;
42 static int iCurrPct, iPrevPct;
43 /* Special treatment for files from the Apple Macintosh */
44 static BOOL bMacFile = FALSE;
45 /* Needed for reading a complete table row */
46 static row_block_type tRowInfo;
47 static BOOL bRowInfo = FALSE;
48 static BOOL bStartRow = FALSE;
49 static BOOL bEndRow = FALSE;
50 static BOOL bIsTableRow = FALSE;
51 /* Needed for finding the start of a style */
52 static const style_block_type *pStyleInfo = NULL;
53 static BOOL bStartStyle = FALSE;
54 /* Needed for finding the start of a font */
55 static const font_block_type *pFontInfo = NULL;
56 static BOOL bStartFont = FALSE;
60 * vUpdateCounters - Update the counters for the hourglass
62 static void
63 vUpdateCounters(void)
65 #if defined(__riscos)
66 uiCharCounter++;
67 iCurrPct = (int)((uiCharCounter * 100) / uiDocumentLength);
68 if (iCurrPct != iPrevPct) {
69 visdelay_percent(iCurrPct);
70 iPrevPct = iCurrPct;
72 #endif /* __riscos */
73 } /* end of vUpdateCounters */
76 * bOutputContainsText - see if the output contains more than white-space
78 static BOOL
79 bOutputContainsText(output_type *pAnchor)
81 output_type *pTmp;
82 int iIndex;
84 fail(pAnchor == NULL);
86 for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
87 fail(pTmp->iStringWidth < 0);
88 for (iIndex = 0; iIndex < pTmp->iNextFree; iIndex++) {
89 if (isspace(pTmp->szStorage[iIndex])) {
90 continue;
92 #if defined(DEBUG)
93 if ((unsigned char)pTmp->szStorage[iIndex] ==
94 FILLER_CHAR) {
95 continue;
97 #endif /* DEBUG */
98 return TRUE;
101 return FALSE;
102 } /* end of bOutputContainsText */
105 * iTotalStringWidth - compute the total width of the output string
107 static int
108 iTotalStringWidth(output_type *pAnchor)
110 output_type *pTmp;
111 int iTotal;
113 iTotal = 0;
114 for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
115 fail(pTmp->iStringWidth < 0);
116 iTotal += pTmp->iStringWidth;
118 return iTotal;
119 } /* end of iTotalStringWidth */
122 * vStoreCharacter - store one character
124 static void
125 vStoreCharacter(int iChar, output_type *pOutput)
127 fail(pOutput == NULL);
129 if (iChar == 0) {
130 pOutput->szStorage[pOutput->iNextFree] = '\0';
131 return;
133 while (pOutput->iNextFree + 2 > pOutput->iStorageSize) {
134 pOutput->iStorageSize += EXTENTION_SIZE;
135 pOutput->szStorage = xrealloc(pOutput->szStorage,
136 pOutput->iStorageSize);
138 pOutput->szStorage[pOutput->iNextFree] = (char)iChar;
139 pOutput->szStorage[pOutput->iNextFree+1] = '\0';
140 pOutput->iStringWidth += iComputeStringWidth(
141 pOutput->szStorage + pOutput->iNextFree,
143 pOutput->tFontRef,
144 pOutput->ucFontsize);
145 pOutput->iNextFree++;
146 } /* end of vStoreCharacter */
149 * vStoreString - store a string
151 static void
152 vStoreString(const char *szString, int iStringLength, output_type *pOutput)
154 int iIndex;
156 fail(szString == NULL || iStringLength < 0 || pOutput == NULL);
158 for (iIndex = 0; iIndex < iStringLength; iIndex++) {
159 vStoreCharacter(szString[iIndex], pOutput);
161 } /* end of vStoreString */
164 * vStoreIntegerAsDecimal - store an integer as a decimal number
166 static void
167 vStoreIntegerAsDecimal(int iNumber, output_type *pOutput)
169 int iLen;
170 char szString[15];
172 fail(pOutput == NULL);
174 iLen = sprintf(szString, "%d", iNumber);
175 vStoreString(szString, iLen, pOutput);
176 } /* end of vStoreIntegerAsDecimal */
179 * vStoreIntegerAsRoman - store an integer as a roman numerical
181 static void
182 vStoreIntegerAsRoman(int iNumber, output_type *pOutput)
184 int iLen;
185 char szString[15];
187 fail(iNumber <= 0);
188 fail(pOutput == NULL);
190 iLen = iInteger2Roman(iNumber, FALSE, szString);
191 vStoreString(szString, iLen, pOutput);
192 } /* end of vStoreIntegerAsRoman */
195 * vStoreStyle - store a style
197 static void
198 vStoreStyle(const style_block_type *pStyleInfo, output_type *pOutput)
200 int iLen;
201 char szString[120];
203 fail(pOutput == NULL);
204 iLen = iStyle2Window(szString, pStyleInfo);
205 vStoreString(szString, iLen, pOutput);
206 } /* end of vStoreStyle */
209 * vPutIndentation - output the given amount of indentation
211 static void
212 vPutIndentation(diagram_type *pDiag, output_type *pOutput, BOOL bUnmarked,
213 int iListNumber, unsigned char ucListType, char cListCharacter,
214 int iLeftIndent)
216 int iLeftIndentation, iWidth, iNextFree;
217 char szLine[30];
219 fail(pDiag == NULL || pOutput == NULL);
220 fail(iListNumber < 0);
221 fail(iLeftIndent < 0);
223 if (iLeftIndent <= 0) {
224 return;
226 iLeftIndentation = iTwips2MilliPoints(iLeftIndent);
227 if (bUnmarked) {
228 vSetLeftIndentation(pDiag, iLeftIndentation);
229 return;
231 fail(iListNumber <= 0 || iscntrl(cListCharacter));
233 switch (ucListType) {
234 case LIST_BULLETS:
235 iNextFree = 0;
236 break;
237 case LIST_ROMAN_NUM_UPPER:
238 case LIST_ROMAN_NUM_LOWER:
239 iNextFree = iInteger2Roman(iListNumber,
240 ucListType == LIST_ROMAN_NUM_UPPER, szLine);
241 break;
242 case LIST_UPPER_ALPHA:
243 case LIST_LOWER_ALPHA:
244 iNextFree = iInteger2Alpha(iListNumber,
245 ucListType == LIST_UPPER_ALPHA, szLine);
246 break;
247 case LIST_ARABIC_NUM:
248 default:
249 iNextFree = sprintf(szLine, "%d", iListNumber);
251 szLine[iNextFree++] = cListCharacter;
252 szLine[iNextFree++] = ' ';
253 szLine[iNextFree] = '\0';
254 iWidth = iComputeStringWidth(szLine, iNextFree,
255 pOutput->tFontRef, pOutput->ucFontsize);
256 iLeftIndentation -= iWidth;
257 if (iLeftIndentation > 0) {
258 vSetLeftIndentation(pDiag, iLeftIndentation);
260 vStoreString(szLine, iNextFree, pOutput);
261 } /* end of vPutIndentation */
264 * vPutNoteSeparator - output a note separator
266 * A note separator is a horizontal line two inches long.
267 * Two inches equals 144000 milliponts.
269 static void
270 vPutNoteSeparator(output_type *pOutput)
272 int iCounter, iChars, iCharWidth;
273 char szOne[2];
275 fail(pOutput == NULL);
277 szOne[0] = OUR_EM_DASH;
278 szOne[1] = '\0';
279 iCharWidth = iComputeStringWidth(szOne, 1,
280 pOutput->tFontRef, pOutput->ucFontsize);
281 DBG_DEC(iCharWidth);
282 iChars = (144000 + iCharWidth / 2) / iCharWidth;
283 DBG_DEC(iChars);
284 for (iCounter = 0; iCounter < iChars; iCounter++) {
285 vStoreCharacter(OUR_EM_DASH, pOutput);
287 } /* end of vPutNoteSeparator */
292 static output_type *
293 pStartNextOutput(output_type *pCurrent)
295 output_type *pNew;
297 if (pCurrent->iNextFree == 0) {
298 /* The current record is empty, re-use */
299 fail(pCurrent->szStorage[0] != '\0');
300 fail(pCurrent->iStringWidth != 0);
301 return pCurrent;
303 /* The current record is in use, make a new one */
304 pNew = xmalloc(sizeof(*pNew));
305 pCurrent->pNext = pNew;
306 pNew->iStorageSize = INITIAL_SIZE;
307 pNew->szStorage = xmalloc(pNew->iStorageSize);
308 pNew->szStorage[0] = '\0';
309 pNew->iNextFree = 0;
310 pNew->iStringWidth = 0;
311 pNew->iColour = 0;
312 pNew->ucFontstyle = FONT_REGULAR;
313 pNew->tFontRef = 0;
314 pNew->ucFontsize = DEFAULT_FONT_SIZE;
315 pNew->pPrev = pCurrent;
316 pNew->pNext = NULL;
317 return pNew;
318 } /* end of pStartNextOutput */
321 * pStartNewOutput
323 static output_type *
324 pStartNewOutput(output_type *pAnchor, output_type *pLeftOver)
326 output_type *pCurr, *pNext;
327 int iColour;
328 draw_fontref tFontRef;
329 unsigned char ucFontstyle, ucFontsize;
331 iColour = FONT_COLOUR_DEFAULT;
332 ucFontstyle = FONT_REGULAR;
333 tFontRef = 0;
334 ucFontsize = DEFAULT_FONT_SIZE;
335 /* Free the old output space */
336 pCurr = pAnchor;
337 while (pCurr != NULL) {
338 pNext = pCurr->pNext;
339 pCurr->szStorage = xfree(pCurr->szStorage);
340 if (pCurr->pNext == NULL) {
341 iColour = pCurr->iColour;
342 ucFontstyle = pCurr->ucFontstyle;
343 tFontRef = pCurr->tFontRef;
344 ucFontsize = pCurr->ucFontsize;
346 pCurr = xfree(pCurr);
347 pCurr = pNext;
349 if (pLeftOver == NULL) {
350 /* Create new output space */
351 pLeftOver = xmalloc(sizeof(*pLeftOver));
352 pLeftOver->iStorageSize = INITIAL_SIZE;
353 pLeftOver->szStorage = xmalloc(pLeftOver->iStorageSize);
354 pLeftOver->szStorage[0] = '\0';
355 pLeftOver->iNextFree = 0;
356 pLeftOver->iStringWidth = 0;
357 pLeftOver->iColour = iColour;
358 pLeftOver->ucFontstyle = ucFontstyle;
359 pLeftOver->tFontRef = tFontRef;
360 pLeftOver->ucFontsize = ucFontsize;
361 pLeftOver->pPrev = NULL;
362 pLeftOver->pNext = NULL;
364 fail(!bCheckDoubleLinkedList(pLeftOver));
365 return pLeftOver;
366 } /* end of pStartNewOutput */
369 * iGetChar - get the next character from the given list
371 static int
372 iGetChar(FILE *pFile, list_id_enum eListID)
374 const font_block_type *pCurr;
375 int iChar, iFileOffset;
376 BOOL bSkip;
378 fail(pFile == NULL);
380 pCurr = pFontInfo;
381 bSkip = FALSE;
382 for (;;) {
383 iChar = iNextChar(pFile, eListID, &iFileOffset);
384 if (iChar == EOF) {
385 return EOF;
388 vUpdateCounters();
390 if (!bStartRow) {
391 bStartRow = bRowInfo &&
392 iFileOffset == tRowInfo.iOffsetStart;
393 NO_DBG_HEX_C(bStartRow, tRowInfo.iOffsetStart);
395 if (!bEndRow) {
396 bEndRow = bRowInfo &&
397 iFileOffset == tRowInfo.iOffsetEnd;
398 NO_DBG_HEX_C(bStartRow, tRowInfo.iOffsetEnd);
400 if (!bStartStyle) {
401 bStartStyle = pStyleInfo != NULL &&
402 iFileOffset == pStyleInfo->iOffset;
403 NO_DBG_HEX_C(bStartStyle, iFileOffset);
405 if (pCurr != NULL && iFileOffset == pCurr->iOffset) {
406 bStartFont = TRUE;
407 NO_DBG_HEX(iFileOffset);
408 pFontInfo = pCurr;
409 pCurr = pGetNextFontInfoListItem(pCurr);
412 /* Skip embedded characters */
413 if (iChar == START_EMBEDDED) {
414 bSkip = TRUE;
415 continue;
417 if (iChar == END_IGNORE || iChar == END_EMBEDDED) {
418 bSkip = FALSE;
419 continue;
421 if (bSkip) {
422 continue;
424 iChar = iTranslateCharacters(iChar, iFileOffset, bMacFile);
425 if (iChar == EOF) {
426 continue;
428 return iChar;
430 } /* end of iGetChar */
433 * vWord2Text
435 void
436 vWord2Text(diagram_type *pDiag, const char *szFilename)
438 options_type tOptions;
439 FILE *pFile;
440 output_type *pAnchor, *pOutput, *pLeftOver;
441 list_id_enum eListID;
442 int iFontsize, iDefaultTabWidth;
443 int iFootnoteNumber, iEndnoteNumber, iLeftIndent;
444 int iChar, iListNumber, iWidthCurr, iWidthMax, iTmp;
445 BOOL bWasTableRow, bTableFontClosed, bUnmarked;
446 BOOL bAllCapitals, bHiddenText;
447 unsigned char ucFontnumber, ucFontcolour, ucTmp;
448 unsigned char ucFontstyle, ucFontstyleMinimal;
449 unsigned char ucListType, ucAlignment;
450 char cListChar;
452 fail(pDiag == NULL || szFilename == NULL || szFilename[0] == '\0');
454 DBG_MSG("vWord2Text");
456 pFile = pOpenDocument(szFilename);
457 if (pFile == NULL) {
458 return;
460 vAddFonts2Diagram(pDiag);
462 /* Initialisation */
463 uiCharCounter = 0;
464 iCurrPct = 0;
465 iPrevPct = -1;
466 uiDocumentLength = uiGetDocumentLength();
467 bMacFile = bFileFromTheMac();
468 iDefaultTabWidth = iGetDefaultTabWidth();
469 DBG_DEC_C(iDefaultTabWidth != 36000, iDefaultTabWidth);
470 bRowInfo = bGetNextRowInfoListItem(&tRowInfo);
471 DBG_HEX_C(bRowInfo, tRowInfo.iOffsetStart);
472 DBG_HEX_C(bRowInfo, tRowInfo.iOffsetEnd);
473 bStartRow = FALSE;
474 bEndRow = FALSE;
475 bIsTableRow = FALSE;
476 bWasTableRow = FALSE;
477 vResetStyles();
478 pStyleInfo = pGetNextStyleInfoListItem();
479 bStartStyle = FALSE;
480 pAnchor = NULL;
481 pFontInfo = pGetNextFontInfoListItem(NULL);
482 DBG_HEX_C(pFontInfo != NULL, pFontInfo->iOffset);
483 DBG_MSG_C(pFontInfo == NULL, "No fonts at all");
484 bStartFont = FALSE;
485 ucFontnumber = 0;
486 ucFontstyleMinimal = FONT_REGULAR;
487 ucFontstyle = FONT_REGULAR;
488 iFontsize = DEFAULT_FONT_SIZE;
489 ucFontcolour = 0;
490 pAnchor = pStartNewOutput(pAnchor, NULL);
491 pOutput = pAnchor;
492 pOutput->iColour = ucFontcolour;
493 pOutput->ucFontstyle = ucFontstyle;
494 pOutput->tFontRef =
495 tOpenFont(pDiag, ucFontnumber, ucFontstyle, iFontsize);
496 pOutput->ucFontsize = iFontsize;
497 bTableFontClosed = TRUE;
498 iLeftIndent = 0;
499 bUnmarked = TRUE;
500 ucListType = LIST_BULLETS;
501 cListChar = OUR_BULLET;
502 iListNumber = 0;
503 ucAlignment = ALIGNMENT_LEFT;
504 bAllCapitals = FALSE;
505 bHiddenText = FALSE;
506 vGetOptions(&tOptions);
507 fail(tOptions.iParagraphBreak < 0);
508 if (tOptions.iParagraphBreak == 0) {
509 iWidthMax = INT_MAX;
510 } else if (tOptions.iParagraphBreak < MIN_SCREEN_WIDTH) {
511 iWidthMax = iChar2MilliPoints(MIN_SCREEN_WIDTH);
512 } else if (tOptions.iParagraphBreak > MAX_SCREEN_WIDTH) {
513 iWidthMax = iChar2MilliPoints(MAX_SCREEN_WIDTH);
514 } else {
515 iWidthMax = iChar2MilliPoints(tOptions.iParagraphBreak);
517 NO_DBG_DEC(iWidthMax);
519 visdelay_begin();
521 iFootnoteNumber = 0;
522 iEndnoteNumber = 0;
523 eListID = text_list;
524 for(;;) {
525 iChar = iGetChar(pFile, eListID);
526 if (iChar == EOF) {
527 if (bOutputContainsText(pAnchor)) {
528 OUTPUT_LINE();
529 } else {
530 RESET_LINE();
532 switch (eListID) {
533 case text_list:
534 eListID = footnote_list;
535 if (iFootnoteNumber > 0) {
536 vPutNoteSeparator(pAnchor);
537 OUTPUT_LINE();
538 iFootnoteNumber = 0;
540 break;
541 case footnote_list:
542 eListID = endnote_list;
543 if (iEndnoteNumber > 0) {
544 vPutNoteSeparator(pAnchor);
545 OUTPUT_LINE();
546 iEndnoteNumber = 0;
548 break;
549 case endnote_list:
550 default:
551 eListID = end_of_lists;
552 break;
554 if (eListID == end_of_lists) {
555 break;
557 continue;
560 if (iChar == UNKNOWN_NOTE_CHAR) {
561 switch (eListID) {
562 case footnote_list:
563 iChar = FOOTNOTE_CHAR;
564 break;
565 case endnote_list:
566 iChar = ENDNOTE_CHAR;
567 break;
568 default:
569 break;
573 if (bStartRow) {
574 /* Begin of a tablerow found */
575 if (bOutputContainsText(pAnchor)) {
576 OUTPUT_LINE();
577 } else {
578 RESET_LINE();
580 fail(pAnchor != pOutput);
581 if (bTableFontClosed) {
582 /* Start special table font */
583 vCloseFont();
585 * Compensate for the fact that Word uses
586 * proportional fonts for its tables and we
587 * only one fixed-width font
589 pOutput->ucFontsize =
590 iFontsize <= DEFAULT_FONT_SIZE ?
591 (DEFAULT_FONT_SIZE * 5 + 3) / 6 :
592 (iFontsize * 5 + 3) / 6;
593 pOutput->tFontRef =
594 tOpenTableFont(pDiag,
595 pOutput->ucFontsize);
596 pOutput->ucFontstyle = FONT_REGULAR;
597 pOutput->iColour = FONT_COLOUR_BLACK;
598 bTableFontClosed = FALSE;
600 bIsTableRow = TRUE;
601 bStartRow = FALSE;
604 if (bWasTableRow &&
605 !bIsTableRow &&
606 iChar != PAR_END &&
607 iChar != HARD_RETURN &&
608 iChar != FORM_FEED &&
609 iChar != COLUMN_FEED) {
611 * The end of a table should be followed by an
612 * empty line, like the end of a paragraph
614 OUTPUT_LINE();
615 vEndOfParagraph2Diagram(pDiag,
616 pOutput->tFontRef,
617 pOutput->ucFontsize);
620 switch (iChar) {
621 case FORM_FEED:
622 case COLUMN_FEED:
623 if (bIsTableRow) {
624 vStoreCharacter('\n', pOutput);
625 break;
627 if (bOutputContainsText(pAnchor)) {
628 OUTPUT_LINE();
629 } else {
630 RESET_LINE();
632 if (iChar == FORM_FEED) {
633 vEndOfPage2Diagram(pDiag,
634 pOutput->tFontRef,
635 pOutput->ucFontsize);
636 } else {
637 vEndOfParagraph2Diagram(pDiag,
638 pOutput->tFontRef,
639 pOutput->ucFontsize);
641 break;
642 default:
643 break;
646 if (bStartFont) {
647 /* Begin of a font found */
648 fail(pFontInfo == NULL);
649 bAllCapitals = bIsCapitals(pFontInfo->ucFontstyle);
650 bHiddenText = bIsHidden(pFontInfo->ucFontstyle);
651 ucTmp = pFontInfo->ucFontstyle &
652 (FONT_BOLD|FONT_ITALIC|FONT_UNDERLINE|FONT_STRIKE);
653 if (!bIsTableRow &&
654 (iFontsize != pFontInfo->ucFontsize ||
655 ucFontnumber != pFontInfo->ucFontnumber ||
656 ucFontstyleMinimal != ucTmp ||
657 ucFontcolour != pFontInfo->ucFontcolour)) {
658 pOutput = pStartNextOutput(pOutput);
659 vCloseFont();
660 pOutput->iColour = pFontInfo->ucFontcolour;
661 pOutput->ucFontstyle = pFontInfo->ucFontstyle;
662 pOutput->ucFontsize = pFontInfo->ucFontsize;
663 pOutput->tFontRef = tOpenFont(
664 pDiag,
665 pFontInfo->ucFontnumber,
666 pFontInfo->ucFontstyle,
667 pFontInfo->ucFontsize);
668 fail(!bCheckDoubleLinkedList(pAnchor));
670 ucFontnumber = pFontInfo->ucFontnumber;
671 iFontsize = pFontInfo->ucFontsize;
672 ucFontcolour = pFontInfo->ucFontcolour;
673 ucFontstyle = pFontInfo->ucFontstyle;
674 ucFontstyleMinimal = ucTmp;
675 pFontInfo = pGetNextFontInfoListItem(pFontInfo);
676 NO_DBG_HEX_C(pFontInfo != NULL, pFontInfo->iOffset);
677 DBG_MSG_C(pFontInfo == NULL, "No more fonts");
678 bStartFont = FALSE;
681 if (bStartStyle) {
682 /* Begin of a style found */
683 fail(pStyleInfo == NULL);
684 if (!bIsTableRow) {
685 vStoreStyle(pStyleInfo, pOutput);
687 iLeftIndent = pStyleInfo->sLeftIndent;
688 bUnmarked = !pStyleInfo->bInList ||
689 pStyleInfo->bUnmarked;
690 ucListType = pStyleInfo->ucListType;
691 cListChar = pStyleInfo->ucListCharacter;
692 ucAlignment = pStyleInfo->ucAlignment;
693 if (pStyleInfo->bInList) {
694 if (!pStyleInfo->bUnmarked) {
695 iListNumber++;
697 } else {
698 iListNumber = 0;
700 pStyleInfo = pGetNextStyleInfoListItem();
701 NO_DBG_HEX_C(pStyleInfo != NULL,pStyleInfo->iOffset);
702 bStartStyle = FALSE;
705 if (!bIsTableRow &&
706 iTotalStringWidth(pAnchor) == 0) {
707 vPutIndentation(pDiag, pAnchor, bUnmarked,
708 iListNumber, ucListType, cListChar,
709 iLeftIndent);
710 /* One mark per paragraph will do */
711 bUnmarked = TRUE;
714 switch (iChar) {
715 case PICTURE:
716 vStoreString("[pic]", 5, pOutput);
717 break;
718 case FOOTNOTE_CHAR:
719 iFootnoteNumber++;
720 vStoreCharacter('[', pOutput);
721 vStoreIntegerAsDecimal(iFootnoteNumber, pOutput);
722 vStoreCharacter(']', pOutput);
723 break;
724 case ENDNOTE_CHAR:
725 iEndnoteNumber++;
726 vStoreCharacter('[', pOutput);
727 vStoreIntegerAsRoman(iEndnoteNumber, pOutput);
728 vStoreCharacter(']', pOutput);
729 break;
730 case UNKNOWN_NOTE_CHAR:
731 vStoreString("[?]", 3, pOutput);
732 break;
733 case PAR_END:
734 if (bIsTableRow) {
735 vStoreCharacter('\n', pOutput);
736 break;
738 if (bOutputContainsText(pAnchor)) {
739 OUTPUT_LINE();
740 } else {
741 RESET_LINE();
743 vEndOfParagraph2Diagram(pDiag,
744 pOutput->tFontRef,
745 pOutput->ucFontsize);
747 * End of paragraph seen, reset indentation,
748 * marking and alignment
750 iLeftIndent = 0;
751 bUnmarked = TRUE;
752 ucAlignment = ALIGNMENT_LEFT;
753 break;
754 case HARD_RETURN:
755 if (bIsTableRow) {
756 vStoreCharacter('\n', pOutput);
757 break;
759 if (bOutputContainsText(pAnchor)) {
760 OUTPUT_LINE();
762 vEmptyLine2Diagram(pDiag,
763 pOutput->tFontRef,
764 pOutput->ucFontsize);
765 break;
766 case FORM_FEED:
767 case COLUMN_FEED:
768 /* Already dealt with */
769 break;
770 case TABLE_SEPARATOR:
771 if (bIsTableRow) {
772 vStoreCharacter(iChar, pOutput);
773 break;
775 vStoreCharacter(' ', pOutput);
776 vStoreCharacter(TABLE_SEPARATOR_CHAR, pOutput);
777 break;
778 case TAB:
779 if (bIsTableRow) {
780 vStoreCharacter(' ', pOutput);
781 break;
783 if (tOptions.iParagraphBreak == 0 &&
784 !tOptions.bUseOutlineFonts) {
785 /* No logical lines, so no tab expansion */
786 vStoreCharacter(TAB, pOutput);
787 break;
789 iTmp = iTotalStringWidth(pAnchor);
790 iTmp += iDrawUnits2MilliPoints(pDiag->iXleft);
791 iTmp /= iDefaultTabWidth;
792 do {
793 vStoreCharacter(FILLER_CHAR, pOutput);
794 iWidthCurr = iTotalStringWidth(pAnchor);
795 iWidthCurr +=
796 iDrawUnits2MilliPoints(pDiag->iXleft);
797 } while (iTmp == iWidthCurr / iDefaultTabWidth &&
798 iWidthCurr < iWidthMax);
799 break;
800 default:
801 if (bHiddenText && tOptions.bHideHiddenText) {
802 continue;
804 if (bAllCapitals && iChar < UCHAR_MAX) {
805 iChar = iToUpper(iChar);
807 vStoreCharacter(iChar, pOutput);
808 break;
811 if (bWasTableRow && !bIsTableRow) {
812 /* End of a table, resume normal font */
813 NO_DBG_MSG("End of table font");
814 vCloseFont();
815 bTableFontClosed = TRUE;
816 pOutput->iColour = ucFontcolour;
817 pOutput->ucFontstyle = ucFontstyle;
818 pOutput->ucFontsize = iFontsize;
819 pOutput->tFontRef = tOpenFont(pDiag, ucFontnumber,
820 ucFontstyle, iFontsize);
822 bWasTableRow = bIsTableRow;
824 if (bIsTableRow) {
825 fail(pAnchor != pOutput);
826 if (!bEndRow) {
827 continue;
829 /* End of a table row */
830 fail(!bRowInfo);
831 vTableRow2Window(pDiag, pAnchor, &tRowInfo);
832 /* Reset */
833 pAnchor = pStartNewOutput(pAnchor, NULL);
834 pOutput = pAnchor;
835 bRowInfo = bGetNextRowInfoListItem(&tRowInfo);
836 bIsTableRow = FALSE;
837 bEndRow = FALSE;
838 NO_DBG_HEX_C(bRowInfo, tRowInfo.iOffsetStart);
839 NO_DBG_HEX_C(bRowInfo, tRowInfo.iOffsetEnd);
840 continue;
842 iWidthCurr = iTotalStringWidth(pAnchor);
843 iWidthCurr += iDrawUnits2MilliPoints(pDiag->iXleft);
844 if (iWidthCurr < iWidthMax) {
845 continue;
847 pLeftOver = pSplitList(pAnchor);
848 vJustify2Window(pDiag, pAnchor, iWidthMax, ucAlignment);
849 pAnchor = pStartNewOutput(pAnchor, pLeftOver);
850 for (pOutput = pAnchor;
851 pOutput->pNext != NULL;
852 pOutput = pOutput->pNext)
853 ; /* EMPTY */
854 fail(pOutput == NULL);
855 if (iTotalStringWidth(pAnchor) > 0) {
856 vSetLeftIndentation(pDiag,
857 iTwips2MilliPoints(iLeftIndent));
861 pAnchor = pStartNewOutput(pAnchor, NULL);
862 pAnchor->szStorage = xfree(pAnchor->szStorage);
863 pAnchor = xfree(pAnchor);
864 vCloseFont();
865 vCloseDocument(pFile);
866 visdelay_end();
867 } /* end of vWord2Text */