mirror of
https://github.com/simon987/antiword.git
synced 2025-04-10 13:06:41 +00:00
1506 lines
38 KiB
C
1506 lines
38 KiB
C
/*
|
|
* word2text.c
|
|
* Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
|
|
*
|
|
* Description:
|
|
* MS Word to "text" functions
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#if defined(__riscos)
|
|
#include "DeskLib:Hourglass.h"
|
|
#include "drawfile.h"
|
|
#endif /* __riscos */
|
|
#include "antiword.h"
|
|
|
|
|
|
#define INITIAL_SIZE 40
|
|
#define EXTENTION_SIZE 20
|
|
|
|
|
|
/* Macros to make sure all such statements will be identical */
|
|
#define OUTPUT_LINE() \
|
|
do {\
|
|
vAlign2Window(pDiag, pAnchor, lWidthMax, ucAlignment);\
|
|
TRACE_MSG("after vAlign2Window");\
|
|
pAnchor = pStartNewOutput(pAnchor, NULL);\
|
|
pOutput = pAnchor;\
|
|
} while(0)
|
|
|
|
#define RESET_LINE() \
|
|
do {\
|
|
pAnchor = pStartNewOutput(pAnchor, NULL);\
|
|
pOutput = pAnchor;\
|
|
} while(0)
|
|
|
|
#if defined(__riscos)
|
|
/* Length of the document in characters */
|
|
static ULONG ulDocumentLength;
|
|
/* Number of characters processed so far */
|
|
static ULONG ulCharCounter;
|
|
static int iCurrPct, iPrevPct;
|
|
#endif /* __riscos */
|
|
/* The document is in the format belonging to this version of Word */
|
|
static int iWordVersion = -1;
|
|
/* Special treatment for files from Word 4/5/6 on an Apple Macintosh */
|
|
static BOOL bOldMacFile = FALSE;
|
|
/* Section Information */
|
|
static const section_block_type *pSection = NULL;
|
|
static const section_block_type *pSectionNext = NULL;
|
|
/* All the (command line) options */
|
|
static options_type tOptions;
|
|
/* Needed for reading a complete table row */
|
|
static const row_block_type *pRowInfo = NULL;
|
|
static BOOL bStartRow = FALSE;
|
|
static BOOL bEndRowNorm = FALSE;
|
|
static BOOL bEndRowFast = FALSE;
|
|
static BOOL bIsTableRow = FALSE;
|
|
/* Index of the next style and font information */
|
|
static USHORT usIstdNext = ISTD_NORMAL;
|
|
/* Needed for finding the start of a style */
|
|
static const style_block_type *pStyleInfo = NULL;
|
|
static style_block_type tStyleNext;
|
|
static BOOL bStartStyle = FALSE;
|
|
static BOOL bStartStyleNext = FALSE;
|
|
/* Needed for finding the start of a font */
|
|
static const font_block_type *pFontInfo = NULL;
|
|
static font_block_type tFontNext;
|
|
static BOOL bStartFont = FALSE;
|
|
static BOOL bStartFontNext = FALSE;
|
|
/* Needed for finding an image */
|
|
static ULONG ulFileOffsetImage = FC_INVALID;
|
|
|
|
|
|
/*
|
|
* vUpdateCounters - Update the counters for the hourglass
|
|
*/
|
|
static void
|
|
vUpdateCounters(void)
|
|
{
|
|
#if defined(__riscos)
|
|
ulCharCounter++;
|
|
iCurrPct = (int)((ulCharCounter * 100) / ulDocumentLength);
|
|
if (iCurrPct != iPrevPct) {
|
|
Hourglass_Percentage(iCurrPct);
|
|
iPrevPct = iCurrPct;
|
|
}
|
|
#endif /* __riscos */
|
|
} /* end of vUpdateCounters */
|
|
|
|
/*
|
|
* bOutputContainsText - see if the output contains more than white space
|
|
*/
|
|
BOOL
|
|
bOutputContainsText(const output_type *pAnchor)
|
|
{
|
|
const output_type *pCurr;
|
|
size_t tIndex;
|
|
|
|
fail(pAnchor == NULL);
|
|
|
|
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
|
|
fail(pCurr->lStringWidth < 0);
|
|
for (tIndex = 0; tIndex < pCurr->tNextFree; tIndex++) {
|
|
if (isspace((int)(UCHAR)pCurr->szStorage[tIndex])) {
|
|
continue;
|
|
}
|
|
#if defined(DEBUG)
|
|
if (pCurr->szStorage[tIndex] == FILLER_CHAR) {
|
|
continue;
|
|
}
|
|
#endif /* DEBUG */
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
} /* end of bOutputContainsText */
|
|
|
|
/*
|
|
* lTotalStringWidth - compute the total width of the output string
|
|
*/
|
|
static long
|
|
lTotalStringWidth(const output_type *pAnchor)
|
|
{
|
|
const output_type *pCurr;
|
|
long lTotal;
|
|
|
|
lTotal = 0;
|
|
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
|
|
DBG_DEC_C(pCurr->lStringWidth < 0, pCurr->lStringWidth);
|
|
fail(pCurr->lStringWidth < 0);
|
|
lTotal += pCurr->lStringWidth;
|
|
}
|
|
return lTotal;
|
|
} /* end of lTotalStringWidth */
|
|
|
|
/*
|
|
* vStoreByte - store one byte
|
|
*/
|
|
static void
|
|
vStoreByte(UCHAR ucChar, output_type *pOutput)
|
|
{
|
|
fail(pOutput == NULL);
|
|
|
|
if (ucChar == 0) {
|
|
pOutput->szStorage[pOutput->tNextFree] = '\0';
|
|
return;
|
|
}
|
|
|
|
while (pOutput->tNextFree + 2 > pOutput->tStorageSize) {
|
|
pOutput->tStorageSize += EXTENTION_SIZE;
|
|
pOutput->szStorage = xrealloc(pOutput->szStorage,
|
|
pOutput->tStorageSize);
|
|
}
|
|
pOutput->szStorage[pOutput->tNextFree] = (char)ucChar;
|
|
pOutput->szStorage[pOutput->tNextFree + 1] = '\0';
|
|
pOutput->tNextFree++;
|
|
} /* end of vStoreByte */
|
|
|
|
/*
|
|
* vStoreChar - store a character as one or more bytes
|
|
*/
|
|
static void
|
|
vStoreChar(ULONG ulChar, BOOL bChangeAllowed, output_type *pOutput)
|
|
{
|
|
char szResult[4];
|
|
size_t tIndex, tLen;
|
|
|
|
fail(pOutput == NULL);
|
|
|
|
if (tOptions.eEncoding == encoding_utf_8 && bChangeAllowed) {
|
|
DBG_HEX_C(ulChar > 0xffff, ulChar);
|
|
fail(ulChar > 0xffff);
|
|
tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
|
|
for (tIndex = 0; tIndex < tLen; tIndex++) {
|
|
vStoreByte((UCHAR)szResult[tIndex], pOutput);
|
|
}
|
|
} else {
|
|
DBG_HEX_C(ulChar > 0xff, ulChar);
|
|
fail(ulChar > 0xff);
|
|
vStoreByte((UCHAR)ulChar, pOutput);
|
|
tLen = 1;
|
|
}
|
|
pOutput->lStringWidth += lComputeStringWidth(
|
|
pOutput->szStorage + pOutput->tNextFree - tLen,
|
|
tLen,
|
|
pOutput->tFontRef,
|
|
pOutput->usFontSize);
|
|
} /* end of vStoreChar */
|
|
|
|
/*
|
|
* vStoreCharacter - store one character
|
|
*/
|
|
static void
|
|
vStoreCharacter(ULONG ulChar, output_type *pOutput)
|
|
{
|
|
vStoreChar(ulChar, TRUE, pOutput);
|
|
} /* end of vStoreCharacter */
|
|
|
|
/*
|
|
* vStoreString - store a string
|
|
*/
|
|
static void
|
|
vStoreString(const char *szString, size_t tStringLength, output_type *pOutput)
|
|
{
|
|
size_t tIndex;
|
|
|
|
fail(szString == NULL || pOutput == NULL);
|
|
|
|
for (tIndex = 0; tIndex < tStringLength; tIndex++) {
|
|
vStoreCharacter((ULONG)(UCHAR)szString[tIndex], pOutput);
|
|
}
|
|
} /* end of vStoreString */
|
|
|
|
/*
|
|
* vStoreNumberAsDecimal - store a number as a decimal number
|
|
*/
|
|
static void
|
|
vStoreNumberAsDecimal(UINT uiNumber, output_type *pOutput)
|
|
{
|
|
size_t tLen;
|
|
char szString[3 * sizeof(UINT) + 1];
|
|
|
|
fail(uiNumber == 0);
|
|
fail(pOutput == NULL);
|
|
|
|
tLen = (size_t)sprintf(szString, "%u", uiNumber);
|
|
vStoreString(szString, tLen, pOutput);
|
|
} /* end of vStoreNumberAsDecimal */
|
|
|
|
/*
|
|
* vStoreNumberAsRoman - store a number as a roman numerical
|
|
*/
|
|
static void
|
|
vStoreNumberAsRoman(UINT uiNumber, output_type *pOutput)
|
|
{
|
|
size_t tLen;
|
|
char szString[15];
|
|
|
|
fail(uiNumber == 0);
|
|
fail(pOutput == NULL);
|
|
|
|
tLen = tNumber2Roman(uiNumber, FALSE, szString);
|
|
vStoreString(szString, tLen, pOutput);
|
|
} /* end of vStoreNumberAsRoman */
|
|
|
|
/*
|
|
* vStoreStyle - store a style
|
|
*/
|
|
static void
|
|
vStoreStyle(diagram_type *pDiag, output_type *pOutput,
|
|
const style_block_type *pStyle)
|
|
{
|
|
size_t tLen;
|
|
char szString[120];
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pOutput == NULL);
|
|
fail(pStyle == NULL);
|
|
|
|
if (tOptions.eConversionType == conversion_xml) {
|
|
vSetHeaders(pDiag, pStyle->usIstd);
|
|
} else {
|
|
tLen = tStyle2Window(szString, sizeof(szString),
|
|
pStyle, pSection);
|
|
vStoreString(szString, tLen, pOutput);
|
|
}
|
|
} /* end of vStoreStyle */
|
|
|
|
/*
|
|
* vPutIndentation - output the specified amount of indentation
|
|
*/
|
|
static void
|
|
vPutIndentation(diagram_type *pDiag, output_type *pOutput,
|
|
BOOL bNoMarks, BOOL bFirstLine,
|
|
UINT uiListNumber, UCHAR ucNFC, const char *szListChar,
|
|
long lLeftIndentation, long lLeftIndentation1)
|
|
{
|
|
long lWidth;
|
|
size_t tIndex, tNextFree;
|
|
char szLine[30];
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pOutput == NULL);
|
|
fail(szListChar == NULL);
|
|
fail(lLeftIndentation < 0);
|
|
|
|
if (tOptions.eConversionType == conversion_xml) {
|
|
/* XML does its own indentation at rendering time */
|
|
return;
|
|
}
|
|
|
|
if (bNoMarks) {
|
|
if (bFirstLine) {
|
|
lLeftIndentation += lLeftIndentation1;
|
|
}
|
|
if (lLeftIndentation < 0) {
|
|
lLeftIndentation = 0;
|
|
}
|
|
vSetLeftIndentation(pDiag, lLeftIndentation);
|
|
return;
|
|
}
|
|
if (lLeftIndentation <= 0) {
|
|
DBG_HEX_C(ucNFC != 0x00, ucNFC);
|
|
vSetLeftIndentation(pDiag, 0);
|
|
return;
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
if (tOptions.eEncoding == encoding_utf_8) {
|
|
fail(strlen(szListChar) > 3);
|
|
} else {
|
|
DBG_HEX_C(iscntrl((int)szListChar[0]), szListChar[0]);
|
|
fail(iscntrl((int)szListChar[0]));
|
|
fail(szListChar[1] != '\0');
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
switch (ucNFC) {
|
|
case LIST_ARABIC_NUM:
|
|
case LIST_NUMBER_TXT:
|
|
tNextFree = (size_t)sprintf(szLine, "%u", uiListNumber);
|
|
break;
|
|
case LIST_UPPER_ROMAN:
|
|
case LIST_LOWER_ROMAN:
|
|
tNextFree = tNumber2Roman(uiListNumber,
|
|
ucNFC == LIST_UPPER_ROMAN, szLine);
|
|
break;
|
|
case LIST_UPPER_ALPHA:
|
|
case LIST_LOWER_ALPHA:
|
|
tNextFree = tNumber2Alpha(uiListNumber,
|
|
ucNFC == LIST_UPPER_ALPHA, szLine);
|
|
break;
|
|
case LIST_ORDINAL_NUM:
|
|
case LIST_ORDINAL_TXT:
|
|
if (uiListNumber % 10 == 1 && uiListNumber != 11) {
|
|
tNextFree =
|
|
(size_t)sprintf(szLine, "%ust", uiListNumber);
|
|
} else if (uiListNumber % 10 == 2 && uiListNumber != 12) {
|
|
tNextFree =
|
|
(size_t)sprintf(szLine, "%und", uiListNumber);
|
|
} else if (uiListNumber % 10 == 3 && uiListNumber != 13) {
|
|
tNextFree =
|
|
(size_t)sprintf(szLine, "%urd", uiListNumber);
|
|
} else {
|
|
tNextFree =
|
|
(size_t)sprintf(szLine, "%uth", uiListNumber);
|
|
}
|
|
break;
|
|
case LIST_OUTLINE_NUM:
|
|
tNextFree = (size_t)sprintf(szLine, "%02u", uiListNumber);
|
|
break;
|
|
case LIST_SPECIAL:
|
|
case LIST_SPECIAL2:
|
|
case LIST_BULLETS:
|
|
tNextFree = 0;
|
|
break;
|
|
default:
|
|
DBG_HEX(ucNFC);
|
|
DBG_FIXME();
|
|
tNextFree = (size_t)sprintf(szLine, "%u", uiListNumber);
|
|
break;
|
|
}
|
|
tNextFree += (size_t)sprintf(szLine + tNextFree, "%.3s", szListChar);
|
|
szLine[tNextFree++] = ' ';
|
|
szLine[tNextFree] = '\0';
|
|
lWidth = lComputeStringWidth(szLine, tNextFree,
|
|
pOutput->tFontRef, pOutput->usFontSize);
|
|
lLeftIndentation -= lWidth;
|
|
if (lLeftIndentation < 0) {
|
|
lLeftIndentation = 0;
|
|
}
|
|
vSetLeftIndentation(pDiag, lLeftIndentation);
|
|
for (tIndex = 0; tIndex < tNextFree; tIndex++) {
|
|
vStoreChar((ULONG)(UCHAR)szLine[tIndex], FALSE, pOutput);
|
|
}
|
|
} /* end of vPutIndentation */
|
|
|
|
/*
|
|
* vPutSeparatorLine - output a separator line
|
|
*
|
|
* A separator line is a horizontal line two inches long.
|
|
* Two inches equals 144000 millipoints.
|
|
*/
|
|
static void
|
|
vPutSeparatorLine(output_type *pOutput)
|
|
{
|
|
long lCharWidth;
|
|
int iCounter, iChars;
|
|
char szOne[2];
|
|
|
|
fail(pOutput == NULL);
|
|
|
|
szOne[0] = OUR_EM_DASH;
|
|
szOne[1] = '\0';
|
|
lCharWidth = lComputeStringWidth(szOne, 1,
|
|
pOutput->tFontRef, pOutput->usFontSize);
|
|
NO_DBG_DEC(lCharWidth);
|
|
iChars = (int)((144000 + lCharWidth / 2) / lCharWidth);
|
|
NO_DBG_DEC(iChars);
|
|
for (iCounter = 0; iCounter < iChars; iCounter++) {
|
|
vStoreCharacter((ULONG)(UCHAR)OUR_EM_DASH, pOutput);
|
|
}
|
|
} /* end of vPutSeparatorLine */
|
|
|
|
/*
|
|
* pStartNextOutput - start the next output record
|
|
*
|
|
* returns a pointer to the next record
|
|
*/
|
|
static output_type *
|
|
pStartNextOutput(output_type *pCurrent)
|
|
{
|
|
output_type *pNew;
|
|
|
|
TRACE_MSG("pStartNextOutput");
|
|
|
|
if (pCurrent->tNextFree == 0) {
|
|
/* The current record is empty, re-use */
|
|
fail(pCurrent->szStorage[0] != '\0');
|
|
fail(pCurrent->lStringWidth != 0);
|
|
return pCurrent;
|
|
}
|
|
/* The current record is in use, make a new one */
|
|
pNew = xmalloc(sizeof(*pNew));
|
|
pCurrent->pNext = pNew;
|
|
pNew->tStorageSize = INITIAL_SIZE;
|
|
pNew->szStorage = xmalloc(pNew->tStorageSize);
|
|
pNew->szStorage[0] = '\0';
|
|
pNew->tNextFree = 0;
|
|
pNew->lStringWidth = 0;
|
|
pNew->ucFontColor = FONT_COLOR_DEFAULT;
|
|
pNew->usFontStyle = FONT_REGULAR;
|
|
pNew->tFontRef = (drawfile_fontref)0;
|
|
pNew->usFontSize = DEFAULT_FONT_SIZE;
|
|
pNew->pPrev = pCurrent;
|
|
pNew->pNext = NULL;
|
|
return pNew;
|
|
} /* end of pStartNextOutput */
|
|
|
|
/*
|
|
* pStartNewOutput
|
|
*/
|
|
static output_type *
|
|
pStartNewOutput(output_type *pAnchor, output_type *pLeftOver)
|
|
{
|
|
output_type *pCurr, *pNext;
|
|
USHORT usFontStyle, usFontSize;
|
|
drawfile_fontref tFontRef;
|
|
UCHAR ucFontColor;
|
|
|
|
TRACE_MSG("pStartNewOutput");
|
|
|
|
ucFontColor = FONT_COLOR_DEFAULT;
|
|
usFontStyle = FONT_REGULAR;
|
|
tFontRef = (drawfile_fontref)0;
|
|
usFontSize = DEFAULT_FONT_SIZE;
|
|
/* Free the old output space */
|
|
pCurr = pAnchor;
|
|
while (pCurr != NULL) {
|
|
TRACE_MSG("Free the old output space");
|
|
pNext = pCurr->pNext;
|
|
pCurr->szStorage = xfree(pCurr->szStorage);
|
|
if (pCurr->pNext == NULL) {
|
|
ucFontColor = pCurr->ucFontColor;
|
|
usFontStyle = pCurr->usFontStyle;
|
|
tFontRef = pCurr->tFontRef;
|
|
usFontSize = pCurr->usFontSize;
|
|
}
|
|
pCurr = xfree(pCurr);
|
|
pCurr = pNext;
|
|
}
|
|
if (pLeftOver == NULL) {
|
|
/* Create new output space */
|
|
TRACE_MSG("Create new output space");
|
|
pLeftOver = xmalloc(sizeof(*pLeftOver));
|
|
pLeftOver->tStorageSize = INITIAL_SIZE;
|
|
NO_DBG_DEC(pLeftOver->tStorageSize);
|
|
TRACE_MSG("before 2nd xmalloc");
|
|
pLeftOver->szStorage = xmalloc(pLeftOver->tStorageSize);
|
|
TRACE_MSG("after 2nd xmalloc");
|
|
pLeftOver->szStorage[0] = '\0';
|
|
pLeftOver->tNextFree = 0;
|
|
pLeftOver->lStringWidth = 0;
|
|
pLeftOver->ucFontColor = ucFontColor;
|
|
pLeftOver->usFontStyle = usFontStyle;
|
|
pLeftOver->tFontRef = tFontRef;
|
|
pLeftOver->usFontSize = usFontSize;
|
|
pLeftOver->pPrev = NULL;
|
|
pLeftOver->pNext = NULL;
|
|
}
|
|
fail(!bCheckDoubleLinkedList(pLeftOver));
|
|
return pLeftOver;
|
|
} /* end of pStartNewOutput */
|
|
|
|
/*
|
|
* ulGetChar - get the next character from the specified list
|
|
*
|
|
* returns the next character of EOF
|
|
*/
|
|
static ULONG
|
|
ulGetChar(FILE *pFile, list_id_enum eListID)
|
|
{
|
|
const font_block_type *pCurr;
|
|
ULONG ulChar, ulFileOffset, ulCharPos;
|
|
row_info_enum eRowInfo;
|
|
USHORT usChar, usPropMod;
|
|
BOOL bSkip;
|
|
|
|
fail(pFile == NULL);
|
|
|
|
pCurr = pFontInfo;
|
|
bSkip = FALSE;
|
|
for (;;) {
|
|
usChar = usNextChar(pFile, eListID,
|
|
&ulFileOffset, &ulCharPos, &usPropMod);
|
|
if (usChar == (USHORT)EOF) {
|
|
return (ULONG)EOF;
|
|
}
|
|
|
|
vUpdateCounters();
|
|
|
|
eRowInfo = ePropMod2RowInfo(usPropMod, iWordVersion);
|
|
if (!bStartRow) {
|
|
#if 0
|
|
bStartRow = eRowInfo == found_a_cell ||
|
|
(pRowInfo != NULL &&
|
|
ulFileOffset == pRowInfo->ulFileOffsetStart &&
|
|
eRowInfo != found_not_a_cell);
|
|
#else
|
|
bStartRow = pRowInfo != NULL &&
|
|
ulFileOffset == pRowInfo->ulFileOffsetStart;
|
|
#endif
|
|
NO_DBG_HEX_C(bStartRow, pRowInfo->ulFileOffsetStart);
|
|
}
|
|
if (!bEndRowNorm) {
|
|
#if 0
|
|
bEndRow = eRowInfo == found_end_of_row ||
|
|
(pRowInfo != NULL &&
|
|
ulFileOffset == pRowInfo->ulFileOffsetEnd &&
|
|
eRowInfo != found_not_end_of_row);
|
|
#else
|
|
bEndRowNorm = pRowInfo != NULL &&
|
|
ulFileOffset == pRowInfo->ulFileOffsetEnd;
|
|
#endif
|
|
NO_DBG_HEX_C(bEndRowNorm, pRowInfo->ulFileOffsetEnd);
|
|
}
|
|
if (!bEndRowFast) {
|
|
bEndRowFast = eRowInfo == found_end_of_row;
|
|
NO_DBG_HEX_C(bEndRowFast, pRowInfo->ulFileOffsetEnd);
|
|
}
|
|
|
|
if (!bStartStyle) {
|
|
bStartStyle = pStyleInfo != NULL &&
|
|
ulFileOffset == pStyleInfo->ulFileOffset;
|
|
NO_DBG_HEX_C(bStartStyle, ulFileOffset);
|
|
}
|
|
if (pCurr != NULL && ulFileOffset == pCurr->ulFileOffset) {
|
|
bStartFont = TRUE;
|
|
NO_DBG_HEX(ulFileOffset);
|
|
pFontInfo = pCurr;
|
|
pCurr = pGetNextFontInfoListItem(pCurr);
|
|
}
|
|
|
|
/* Skip embedded characters */
|
|
if (usChar == START_EMBEDDED) {
|
|
bSkip = TRUE;
|
|
continue;
|
|
}
|
|
if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
|
|
bSkip = FALSE;
|
|
continue;
|
|
}
|
|
if (bSkip) {
|
|
continue;
|
|
}
|
|
ulChar = ulTranslateCharacters(usChar,
|
|
ulFileOffset,
|
|
iWordVersion,
|
|
tOptions.eConversionType,
|
|
tOptions.eEncoding,
|
|
bOldMacFile);
|
|
if (ulChar == IGNORE_CHARACTER) {
|
|
continue;
|
|
}
|
|
if (ulChar == PICTURE) {
|
|
ulFileOffsetImage = ulGetPictInfoListItem(ulFileOffset);
|
|
} else {
|
|
ulFileOffsetImage = FC_INVALID;
|
|
}
|
|
if (ulChar == PAR_END) {
|
|
/* End of paragraph seen, prepare for the next */
|
|
vFillStyleFromStylesheet(usIstdNext, &tStyleNext);
|
|
vCorrectStyleValues(&tStyleNext);
|
|
bStartStyleNext = TRUE;
|
|
vFillFontFromStylesheet(usIstdNext, &tFontNext);
|
|
vCorrectFontValues(&tFontNext);
|
|
bStartFontNext = TRUE;
|
|
}
|
|
if (ulChar == PAGE_BREAK) {
|
|
/* Might be the start of a new section */
|
|
pSectionNext = pGetSectionInfo(pSection, ulCharPos);
|
|
}
|
|
return ulChar;
|
|
}
|
|
} /* end of ulGetChar */
|
|
|
|
/*
|
|
* lGetWidthMax - get the maximum line width from the paragraph break value
|
|
*
|
|
* Returns the maximum line width in millipoints
|
|
*/
|
|
static long
|
|
lGetWidthMax(int iParagraphBreak)
|
|
{
|
|
fail(iParagraphBreak < 0);
|
|
|
|
if (iParagraphBreak == 0) {
|
|
return LONG_MAX;
|
|
}
|
|
if (iParagraphBreak < MIN_SCREEN_WIDTH) {
|
|
return lChar2MilliPoints(MIN_SCREEN_WIDTH);
|
|
}
|
|
if (iParagraphBreak > MAX_SCREEN_WIDTH) {
|
|
return lChar2MilliPoints(MAX_SCREEN_WIDTH);
|
|
}
|
|
return lChar2MilliPoints(iParagraphBreak);
|
|
} /* end of lGetWidthMax */
|
|
|
|
/*
|
|
* bWordDecryptor - turn Word to something more useful
|
|
*
|
|
* returns TRUE when succesful, otherwise FALSE
|
|
*/
|
|
BOOL
|
|
bWordDecryptor(FILE *pFile, long lFilesize, diagram_type *pDiag)
|
|
{
|
|
imagedata_type tImage;
|
|
const style_block_type *pStyleTmp;
|
|
const font_block_type *pFontTmp;
|
|
const char *szListChar;
|
|
output_type *pAnchor, *pOutput, *pLeftOver;
|
|
ULONG ulChar;
|
|
long lBeforeIndentation, lAfterIndentation;
|
|
long lLeftIndentation, lLeftIndentation1, lRightIndentation;
|
|
long lWidthCurr, lWidthMax, lDefaultTabWidth, lHalfSpaceWidth, lTmp;
|
|
list_id_enum eListID;
|
|
image_info_enum eRes;
|
|
UINT uiFootnoteNumber, uiEndnoteNumber, uiTmp;
|
|
int iListSeqNumber;
|
|
BOOL bWasTableRow, bTableFontClosed, bWasEndOfParagraph;
|
|
BOOL bInList, bWasInList, bNoMarks, bFirstLine;
|
|
BOOL bAllCapitals, bHiddenText, bMarkDelText, bSuccess;
|
|
USHORT usListNumber;
|
|
USHORT usFontStyle, usFontStyleMinimal, usFontSize, usTmp;
|
|
UCHAR ucFontNumber, ucFontColor;
|
|
UCHAR ucNFC, ucAlignment;
|
|
|
|
fail(pFile == NULL || lFilesize <= 0 || pDiag == NULL);
|
|
|
|
TRACE_MSG("bWordDecryptor");
|
|
|
|
iWordVersion = iInitDocument(pFile, lFilesize);
|
|
if (iWordVersion < 0) {
|
|
DBG_DEC(iWordVersion);
|
|
return FALSE;
|
|
}
|
|
|
|
vGetOptions(&tOptions);
|
|
bOldMacFile = bIsOldMacFile();
|
|
vPrepareHdrFtrText(pFile);
|
|
vPrepareFootnoteText(pFile);
|
|
|
|
vPrologue2(pDiag, iWordVersion);
|
|
|
|
/* Initialisation */
|
|
#if defined(__riscos)
|
|
ulCharCounter = 0;
|
|
iCurrPct = 0;
|
|
iPrevPct = -1;
|
|
ulDocumentLength = ulGetDocumentLength();
|
|
#endif /* __riscos */
|
|
pSection = pGetSectionInfo(NULL, 0);
|
|
pSectionNext = pSection;
|
|
lDefaultTabWidth = lGetDefaultTabWidth();
|
|
DBG_DEC_C(lDefaultTabWidth != 36000, lDefaultTabWidth);
|
|
pRowInfo = pGetNextRowInfoListItem();
|
|
DBG_HEX_C(pRowInfo != NULL, pRowInfo->ulFileOffsetStart);
|
|
DBG_HEX_C(pRowInfo != NULL, pRowInfo->ulFileOffsetEnd);
|
|
DBG_MSG_C(pRowInfo == NULL, "No rows at all");
|
|
bStartRow = FALSE;
|
|
bEndRowNorm = FALSE;
|
|
bEndRowFast = FALSE;
|
|
bIsTableRow = FALSE;
|
|
bWasTableRow = FALSE;
|
|
vResetStyles();
|
|
pStyleInfo = pGetNextTextStyle(NULL);
|
|
bStartStyle = FALSE;
|
|
bInList = FALSE;
|
|
bWasInList = FALSE;
|
|
iListSeqNumber = 0;
|
|
usIstdNext = ISTD_NORMAL;
|
|
pAnchor = NULL;
|
|
pFontInfo = pGetNextFontInfoListItem(NULL);
|
|
DBG_HEX_C(pFontInfo != NULL, pFontInfo->ulFileOffset);
|
|
DBG_MSG_C(pFontInfo == NULL, "No fonts at all");
|
|
bStartFont = FALSE;
|
|
ucFontNumber = 0;
|
|
usFontStyleMinimal = FONT_REGULAR;
|
|
usFontStyle = FONT_REGULAR;
|
|
usFontSize = DEFAULT_FONT_SIZE;
|
|
ucFontColor = FONT_COLOR_DEFAULT;
|
|
pAnchor = pStartNewOutput(pAnchor, NULL);
|
|
pOutput = pAnchor;
|
|
pOutput->ucFontColor = ucFontColor;
|
|
pOutput->usFontStyle = usFontStyle;
|
|
pOutput->tFontRef = tOpenFont(ucFontNumber, usFontStyle, usFontSize);
|
|
pOutput->usFontSize = usFontSize;
|
|
bTableFontClosed = TRUE;
|
|
lBeforeIndentation = 0;
|
|
lAfterIndentation = 0;
|
|
lLeftIndentation = 0;
|
|
lLeftIndentation1 = 0;
|
|
lRightIndentation = 0;
|
|
bWasEndOfParagraph = TRUE;
|
|
bNoMarks = TRUE;
|
|
bFirstLine = TRUE;
|
|
ucNFC = LIST_BULLETS;
|
|
if (pStyleInfo != NULL) {
|
|
szListChar = pStyleInfo->szListChar;
|
|
pStyleTmp = pStyleInfo;
|
|
} else {
|
|
if (tStyleNext.szListChar[0] == '\0') {
|
|
vGetBulletValue(tOptions.eConversionType,
|
|
tOptions.eEncoding, tStyleNext.szListChar, 4);
|
|
}
|
|
szListChar = tStyleNext.szListChar;
|
|
pStyleTmp = &tStyleNext;
|
|
}
|
|
usListNumber = 0;
|
|
ucAlignment = ALIGNMENT_LEFT;
|
|
bAllCapitals = FALSE;
|
|
bHiddenText = FALSE;
|
|
bMarkDelText = FALSE;
|
|
lWidthMax = lGetWidthMax(tOptions.iParagraphBreak);
|
|
NO_DBG_DEC(lWidthMax);
|
|
|
|
Hourglass_On();
|
|
|
|
uiFootnoteNumber = 0;
|
|
uiEndnoteNumber = 0;
|
|
eListID = text_list;
|
|
for(;;) {
|
|
ulChar = ulGetChar(pFile, eListID);
|
|
if (ulChar == (ULONG)EOF) {
|
|
if (bOutputContainsText(pAnchor)) {
|
|
OUTPUT_LINE();
|
|
} else {
|
|
RESET_LINE();
|
|
}
|
|
switch (eListID) {
|
|
case text_list:
|
|
if (tOptions.eConversionType !=
|
|
conversion_xml) {
|
|
eListID = footnote_list;
|
|
if (uiFootnoteNumber != 0) {
|
|
vPutSeparatorLine(pAnchor);
|
|
OUTPUT_LINE();
|
|
uiFootnoteNumber = 0;
|
|
}
|
|
break;
|
|
}
|
|
/* No break or return */
|
|
case footnote_list:
|
|
eListID = endnote_list;
|
|
if (uiEndnoteNumber != 0) {
|
|
vPutSeparatorLine(pAnchor);
|
|
OUTPUT_LINE();
|
|
uiEndnoteNumber = 0;
|
|
}
|
|
break;
|
|
case endnote_list:
|
|
eListID = textbox_list;
|
|
if (bExistsTextBox()) {
|
|
vPutSeparatorLine(pAnchor);
|
|
OUTPUT_LINE();
|
|
}
|
|
break;
|
|
case textbox_list:
|
|
eListID = hdrtextbox_list;
|
|
if (bExistsHdrTextBox()) {
|
|
vPutSeparatorLine(pAnchor);
|
|
OUTPUT_LINE();
|
|
}
|
|
break;
|
|
case hdrtextbox_list:
|
|
default:
|
|
eListID = end_of_lists;
|
|
break;
|
|
}
|
|
if (eListID == end_of_lists) {
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (ulChar == UNKNOWN_NOTE_CHAR) {
|
|
switch (eListID) {
|
|
case footnote_list:
|
|
ulChar = FOOTNOTE_CHAR;
|
|
break;
|
|
case endnote_list:
|
|
ulChar = ENDNOTE_CHAR;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bStartRow) {
|
|
/* Begin of a tablerow found */
|
|
if (bOutputContainsText(pAnchor)) {
|
|
OUTPUT_LINE();
|
|
} else {
|
|
RESET_LINE();
|
|
}
|
|
fail(pAnchor != pOutput);
|
|
if (bTableFontClosed) {
|
|
/* Start special table font */
|
|
vCloseFont();
|
|
/*
|
|
* Compensate for the fact that Word uses
|
|
* proportional fonts for its tables and we
|
|
* only one fixed-width font
|
|
*/
|
|
uiTmp = ((UINT)usFontSize * 5 + 3) / 6;
|
|
if (uiTmp < MIN_TABLEFONT_SIZE) {
|
|
uiTmp = MIN_TABLEFONT_SIZE;
|
|
} else if (uiTmp > MAX_TABLEFONT_SIZE) {
|
|
uiTmp = MAX_TABLEFONT_SIZE;
|
|
}
|
|
pOutput->usFontSize = (USHORT)uiTmp;
|
|
pOutput->tFontRef =
|
|
tOpenTableFont(pOutput->usFontSize);
|
|
pOutput->usFontStyle = FONT_REGULAR;
|
|
pOutput->ucFontColor = FONT_COLOR_BLACK;
|
|
bTableFontClosed = FALSE;
|
|
}
|
|
bIsTableRow = TRUE;
|
|
bStartRow = FALSE;
|
|
}
|
|
|
|
if (bWasTableRow &&
|
|
!bIsTableRow &&
|
|
ulChar != PAR_END &&
|
|
ulChar != HARD_RETURN &&
|
|
ulChar != PAGE_BREAK &&
|
|
ulChar != COLUMN_FEED) {
|
|
/*
|
|
* The end of a table should be followed by an
|
|
* empty line, like the end of a paragraph
|
|
*/
|
|
OUTPUT_LINE();
|
|
vEndOfParagraph(pDiag,
|
|
pOutput->tFontRef,
|
|
pOutput->usFontSize,
|
|
(long)pOutput->usFontSize * 600);
|
|
}
|
|
|
|
switch (ulChar) {
|
|
case PAGE_BREAK:
|
|
case COLUMN_FEED:
|
|
if (bIsTableRow) {
|
|
/* Ignore when in a table */
|
|
break;
|
|
}
|
|
if (bOutputContainsText(pAnchor)) {
|
|
OUTPUT_LINE();
|
|
} else {
|
|
RESET_LINE();
|
|
}
|
|
if (ulChar == PAGE_BREAK) {
|
|
vEndOfPage(pDiag, lAfterIndentation,
|
|
pSection != pSectionNext);
|
|
} else {
|
|
vEndOfParagraph(pDiag,
|
|
pOutput->tFontRef,
|
|
pOutput->usFontSize,
|
|
lAfterIndentation);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (bStartFont || (bStartFontNext && ulChar != PAR_END)) {
|
|
/* Begin of a font found */
|
|
if (bStartFont) {
|
|
/* bStartFont takes priority */
|
|
fail(pFontInfo == NULL);
|
|
pFontTmp = pFontInfo;
|
|
} else {
|
|
pFontTmp = &tFontNext;
|
|
}
|
|
bAllCapitals = bIsCapitals(pFontTmp->usFontStyle);
|
|
bHiddenText = bIsHidden(pFontTmp->usFontStyle);
|
|
bMarkDelText = bIsMarkDel(pFontTmp->usFontStyle);
|
|
usTmp = pFontTmp->usFontStyle &
|
|
(FONT_BOLD|FONT_ITALIC|FONT_UNDERLINE|
|
|
FONT_STRIKE|FONT_MARKDEL|
|
|
FONT_SUPERSCRIPT|FONT_SUBSCRIPT);
|
|
if (!bIsTableRow &&
|
|
(usFontSize != pFontTmp->usFontSize ||
|
|
ucFontNumber != pFontTmp->ucFontNumber ||
|
|
usFontStyleMinimal != usTmp ||
|
|
ucFontColor != pFontTmp->ucFontColor)) {
|
|
pOutput = pStartNextOutput(pOutput);
|
|
vCloseFont();
|
|
pOutput->ucFontColor = pFontTmp->ucFontColor;
|
|
pOutput->usFontStyle = pFontTmp->usFontStyle;
|
|
pOutput->usFontSize = pFontTmp->usFontSize;
|
|
pOutput->tFontRef = tOpenFont(
|
|
pFontTmp->ucFontNumber,
|
|
pFontTmp->usFontStyle,
|
|
pFontTmp->usFontSize);
|
|
fail(!bCheckDoubleLinkedList(pAnchor));
|
|
}
|
|
ucFontNumber = pFontTmp->ucFontNumber;
|
|
usFontSize = pFontTmp->usFontSize;
|
|
ucFontColor = pFontTmp->ucFontColor;
|
|
usFontStyle = pFontTmp->usFontStyle;
|
|
usFontStyleMinimal = usTmp;
|
|
if (bStartFont) {
|
|
/* Get the next font info */
|
|
pFontInfo = pGetNextFontInfoListItem(pFontInfo);
|
|
NO_DBG_HEX_C(pFontInfo != NULL,
|
|
pFontInfo->ulFileOffset);
|
|
DBG_MSG_C(pFontInfo == NULL, "No more fonts");
|
|
}
|
|
bStartFont = FALSE;
|
|
bStartFontNext = FALSE;
|
|
}
|
|
|
|
if (bStartStyle || (bStartStyleNext && ulChar != PAR_END)) {
|
|
bFirstLine = TRUE;
|
|
/* Begin of a style found */
|
|
if (bStartStyle) {
|
|
/* bStartStyle takes priority */
|
|
fail(pStyleInfo == NULL);
|
|
pStyleTmp = pStyleInfo;
|
|
} else {
|
|
pStyleTmp = &tStyleNext;
|
|
}
|
|
if (!bIsTableRow) {
|
|
vStoreStyle(pDiag, pOutput, pStyleTmp);
|
|
}
|
|
usIstdNext = pStyleTmp->usIstdNext;
|
|
lBeforeIndentation =
|
|
lTwips2MilliPoints(pStyleTmp->usBeforeIndent);
|
|
lAfterIndentation =
|
|
lTwips2MilliPoints(pStyleTmp->usAfterIndent);
|
|
lLeftIndentation =
|
|
lTwips2MilliPoints(pStyleTmp->sLeftIndent);
|
|
lLeftIndentation1 =
|
|
lTwips2MilliPoints(pStyleTmp->sLeftIndent1);
|
|
lRightIndentation =
|
|
lTwips2MilliPoints(pStyleTmp->sRightIndent);
|
|
bInList = bStyleImpliesList(pStyleTmp, iWordVersion);
|
|
bNoMarks = !bInList || pStyleTmp->bNumPause;
|
|
ucNFC = pStyleTmp->ucNFC;
|
|
szListChar = pStyleTmp->szListChar;
|
|
ucAlignment = pStyleTmp->ucAlignment;
|
|
if (bInList && !bWasInList) {
|
|
/* Start of a list */
|
|
iListSeqNumber++;
|
|
vStartOfList(pDiag, ucNFC,
|
|
bWasTableRow && !bIsTableRow);
|
|
}
|
|
if (!bInList && bWasInList) {
|
|
/* End of a list */
|
|
vEndOfList(pDiag);
|
|
}
|
|
bWasInList = bInList;
|
|
if (bStartStyle) {
|
|
pStyleInfo = pGetNextTextStyle(pStyleInfo);
|
|
NO_DBG_HEX_C(pStyleInfo != NULL,
|
|
pStyleInfo->ulFileOffset);
|
|
DBG_MSG_C(pStyleInfo == NULL,
|
|
"No more styles");
|
|
}
|
|
bStartStyle = FALSE;
|
|
bStartStyleNext = FALSE;
|
|
}
|
|
|
|
if (bWasEndOfParagraph) {
|
|
vStartOfParagraph1(pDiag, lBeforeIndentation);
|
|
}
|
|
|
|
if (!bIsTableRow &&
|
|
lTotalStringWidth(pAnchor) == 0) {
|
|
if (!bNoMarks) {
|
|
usListNumber = usGetListValue(iListSeqNumber,
|
|
iWordVersion,
|
|
pStyleTmp);
|
|
}
|
|
if (bInList && bFirstLine) {
|
|
vStartOfListItem(pDiag, bNoMarks);
|
|
}
|
|
vPutIndentation(pDiag, pAnchor, bNoMarks, bFirstLine,
|
|
usListNumber, ucNFC, szListChar,
|
|
lLeftIndentation, lLeftIndentation1);
|
|
bFirstLine = FALSE;
|
|
/* One number or mark per paragraph will do */
|
|
bNoMarks = TRUE;
|
|
}
|
|
|
|
if (bWasEndOfParagraph) {
|
|
vStartOfParagraph2(pDiag);
|
|
bWasEndOfParagraph = FALSE;
|
|
}
|
|
|
|
switch (ulChar) {
|
|
case PICTURE:
|
|
(void)memset(&tImage, 0, sizeof(tImage));
|
|
eRes = eExamineImage(pFile, ulFileOffsetImage, &tImage);
|
|
switch (eRes) {
|
|
case image_no_information:
|
|
bSuccess = FALSE;
|
|
break;
|
|
case image_minimal_information:
|
|
case image_full_information:
|
|
#if 0
|
|
if (bOutputContainsText(pAnchor)) {
|
|
OUTPUT_LINE();
|
|
} else {
|
|
RESET_LINE();
|
|
}
|
|
#endif
|
|
bSuccess = bTranslateImage(pDiag, pFile,
|
|
eRes == image_minimal_information,
|
|
ulFileOffsetImage, &tImage);
|
|
break;
|
|
default:
|
|
DBG_DEC(eRes);
|
|
bSuccess = FALSE;
|
|
break;
|
|
}
|
|
if (!bSuccess) {
|
|
vStoreString("[pic]", 5, pOutput);
|
|
}
|
|
break;
|
|
case FOOTNOTE_CHAR:
|
|
uiFootnoteNumber++;
|
|
if (tOptions.eConversionType == conversion_xml) {
|
|
vStoreCharacter((ULONG)FOOTNOTE_OR_ENDNOTE,
|
|
pOutput);
|
|
break;
|
|
}
|
|
vStoreCharacter((ULONG)'[', pOutput);
|
|
vStoreNumberAsDecimal(uiFootnoteNumber, pOutput);
|
|
vStoreCharacter((ULONG)']', pOutput);
|
|
break;
|
|
case ENDNOTE_CHAR:
|
|
uiEndnoteNumber++;
|
|
vStoreCharacter((ULONG)'[', pOutput);
|
|
vStoreNumberAsRoman(uiEndnoteNumber, pOutput);
|
|
vStoreCharacter((ULONG)']', pOutput);
|
|
break;
|
|
case UNKNOWN_NOTE_CHAR:
|
|
vStoreString("[?]", 3, pOutput);
|
|
break;
|
|
case PAR_END:
|
|
if (bIsTableRow) {
|
|
vStoreCharacter((ULONG)'\n', pOutput);
|
|
break;
|
|
}
|
|
if (bOutputContainsText(pAnchor)) {
|
|
OUTPUT_LINE();
|
|
} else {
|
|
vMove2NextLine(pDiag,
|
|
pOutput->tFontRef, pOutput->usFontSize);
|
|
RESET_LINE();
|
|
}
|
|
vEndOfParagraph(pDiag,
|
|
pOutput->tFontRef,
|
|
pOutput->usFontSize,
|
|
lAfterIndentation);
|
|
bWasEndOfParagraph = TRUE;
|
|
break;
|
|
case HARD_RETURN:
|
|
if (bIsTableRow) {
|
|
vStoreCharacter((ULONG)'\n', pOutput);
|
|
break;
|
|
}
|
|
if (bOutputContainsText(pAnchor)) {
|
|
OUTPUT_LINE();
|
|
} else {
|
|
vMove2NextLine(pDiag,
|
|
pOutput->tFontRef, pOutput->usFontSize);
|
|
RESET_LINE();
|
|
}
|
|
break;
|
|
case PAGE_BREAK:
|
|
case COLUMN_FEED:
|
|
pSection = pSectionNext;
|
|
break;
|
|
case TABLE_SEPARATOR:
|
|
if (bIsTableRow) {
|
|
vStoreCharacter(ulChar, pOutput);
|
|
break;
|
|
}
|
|
vStoreCharacter((ULONG)' ', pOutput);
|
|
vStoreCharacter((ULONG)TABLE_SEPARATOR_CHAR, pOutput);
|
|
break;
|
|
case TAB:
|
|
if (bIsTableRow ||
|
|
tOptions.eConversionType == conversion_xml) {
|
|
vStoreCharacter((ULONG)' ', pOutput);
|
|
break;
|
|
}
|
|
if (tOptions.iParagraphBreak == 0 &&
|
|
(tOptions.eConversionType == conversion_text ||
|
|
tOptions.eConversionType == conversion_fmt_text)) {
|
|
/* No logical lines, so no tab expansion */
|
|
vStoreCharacter(TAB, pOutput);
|
|
break;
|
|
}
|
|
lHalfSpaceWidth = (lComputeSpaceWidth(
|
|
pOutput->tFontRef,
|
|
pOutput->usFontSize) + 1) / 2;
|
|
lTmp = lTotalStringWidth(pAnchor);
|
|
lTmp += lDrawUnits2MilliPoints(pDiag->lXleft);
|
|
lTmp /= lDefaultTabWidth;
|
|
do {
|
|
vStoreCharacter((ULONG)FILLER_CHAR, pOutput);
|
|
lWidthCurr = lTotalStringWidth(pAnchor);
|
|
lWidthCurr +=
|
|
lDrawUnits2MilliPoints(pDiag->lXleft);
|
|
} while (lTmp == lWidthCurr / lDefaultTabWidth &&
|
|
lWidthCurr < lWidthMax + lRightIndentation);
|
|
break;
|
|
default:
|
|
if (bHiddenText && tOptions.bHideHiddenText) {
|
|
continue;
|
|
}
|
|
if (bMarkDelText && tOptions.bRemoveRemovedText) {
|
|
continue;
|
|
}
|
|
if (ulChar == UNICODE_ELLIPSIS &&
|
|
tOptions.eEncoding != encoding_utf_8) {
|
|
vStoreString("...", 3, pOutput);
|
|
} else {
|
|
if (bAllCapitals) {
|
|
ulChar = ulToUpper(ulChar);
|
|
}
|
|
vStoreCharacter(ulChar, pOutput);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (bWasTableRow && !bIsTableRow) {
|
|
/* End of a table */
|
|
vEndOfTable(pDiag);
|
|
/* Resume normal font */
|
|
NO_DBG_MSG("End of table font");
|
|
vCloseFont();
|
|
bTableFontClosed = TRUE;
|
|
pOutput->ucFontColor = ucFontColor;
|
|
pOutput->usFontStyle = usFontStyle;
|
|
pOutput->usFontSize = usFontSize;
|
|
pOutput->tFontRef = tOpenFont(
|
|
ucFontNumber, usFontStyle, usFontSize);
|
|
}
|
|
bWasTableRow = bIsTableRow;
|
|
|
|
if (bIsTableRow) {
|
|
fail(pAnchor != pOutput);
|
|
if (!bEndRowNorm && !bEndRowFast) {
|
|
continue;
|
|
}
|
|
/* End of a table row */
|
|
if (bEndRowNorm) {
|
|
fail(pRowInfo == NULL);
|
|
vTableRow2Window(pDiag, pAnchor, pRowInfo,
|
|
tOptions.eConversionType,
|
|
tOptions.iParagraphBreak);
|
|
} else {
|
|
fail(!bEndRowFast);
|
|
}
|
|
/* Reset */
|
|
pAnchor = pStartNewOutput(pAnchor, NULL);
|
|
pOutput = pAnchor;
|
|
if (bEndRowNorm) {
|
|
pRowInfo = pGetNextRowInfoListItem();
|
|
}
|
|
bIsTableRow = FALSE;
|
|
bEndRowNorm = FALSE;
|
|
bEndRowFast = FALSE;
|
|
NO_DBG_HEX_C(pRowInfo != NULL,
|
|
pRowInfo->ulFileOffsetStart);
|
|
NO_DBG_HEX_C(pRowInfo != NULL,
|
|
pRowInfo->ulFileOffsetEnd);
|
|
continue;
|
|
}
|
|
lWidthCurr = lTotalStringWidth(pAnchor);
|
|
lWidthCurr += lDrawUnits2MilliPoints(pDiag->lXleft);
|
|
if (lWidthCurr < lWidthMax + lRightIndentation) {
|
|
continue;
|
|
}
|
|
pLeftOver = pSplitList(pAnchor);
|
|
vJustify2Window(pDiag, pAnchor,
|
|
lWidthMax, lRightIndentation, ucAlignment);
|
|
pAnchor = pStartNewOutput(pAnchor, pLeftOver);
|
|
for (pOutput = pAnchor;
|
|
pOutput->pNext != NULL;
|
|
pOutput = pOutput->pNext)
|
|
; /* EMPTY */
|
|
fail(pOutput == NULL);
|
|
if (lTotalStringWidth(pAnchor) > 0) {
|
|
vSetLeftIndentation(pDiag, lLeftIndentation);
|
|
}
|
|
}
|
|
|
|
pAnchor = pStartNewOutput(pAnchor, NULL);
|
|
pAnchor->szStorage = xfree(pAnchor->szStorage);
|
|
pAnchor = xfree(pAnchor);
|
|
vCloseFont();
|
|
vFreeDocument();
|
|
Hourglass_Off();
|
|
return TRUE;
|
|
} /* end of bWordDecryptor */
|
|
|
|
/*
|
|
* lLastStringWidth - compute the width of the last part of the output string
|
|
*/
|
|
static long
|
|
lLastStringWidth(const output_type *pAnchor)
|
|
{
|
|
const output_type *pCurr, *pStart;
|
|
|
|
pStart = NULL;
|
|
for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
|
|
if (pCurr->tNextFree == 1 &&
|
|
(pCurr->szStorage[0] == PAR_END ||
|
|
pCurr->szStorage[0] == HARD_RETURN)) {
|
|
/* Found a separator. Start after the separator */
|
|
pStart = pCurr->pNext;
|
|
}
|
|
}
|
|
if (pStart == NULL) {
|
|
/* No separators. Use the whole output string */
|
|
pStart = pAnchor;
|
|
}
|
|
return lTotalStringWidth(pStart);
|
|
} /* end of lLastStringWidth */
|
|
|
|
/*
|
|
* pHdrFtrDecryptor - turn a header/footer list element to something useful
|
|
*/
|
|
output_type *
|
|
pHdrFtrDecryptor(FILE *pFile, ULONG ulCharPosStart, ULONG ulCharPosNext)
|
|
{
|
|
output_type *pAnchor, *pOutput, *pLeftOver;
|
|
ULONG ulChar, ulFileOffset, ulCharPos;
|
|
long lWidthCurr, lWidthMax;
|
|
long lRightIndentation;
|
|
USHORT usChar;
|
|
UCHAR ucAlignment;
|
|
BOOL bSkip;
|
|
|
|
fail(iWordVersion < 0);
|
|
fail(tOptions.eConversionType == conversion_unknown);
|
|
fail(tOptions.eEncoding == 0);
|
|
|
|
if (ulCharPosStart == ulCharPosNext) {
|
|
/* There are no bytes to decrypt */
|
|
return NULL;
|
|
}
|
|
|
|
lRightIndentation = 0;
|
|
ucAlignment = ALIGNMENT_LEFT;
|
|
bSkip = FALSE;
|
|
lWidthMax = lGetWidthMax(tOptions.iParagraphBreak);
|
|
pAnchor = pStartNewOutput(NULL, NULL);
|
|
pOutput = pAnchor;
|
|
pOutput->tFontRef = tOpenFont(0, FONT_REGULAR, DEFAULT_FONT_SIZE);
|
|
usChar = usToHdrFtrPosition(pFile, ulCharPosStart);
|
|
ulCharPos = ulCharPosStart;
|
|
ulFileOffset = ulCharPos2FileOffset(ulCharPos);
|
|
while (usChar != (USHORT)EOF && ulCharPos != ulCharPosNext) {
|
|
/* Skip embedded characters */
|
|
if (usChar == START_EMBEDDED) {
|
|
bSkip = TRUE;
|
|
} else if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
|
|
bSkip = FALSE;
|
|
}
|
|
/* Translate character */
|
|
if (bSkip || usChar == END_IGNORE || usChar == END_EMBEDDED) {
|
|
ulChar = IGNORE_CHARACTER;
|
|
} else {
|
|
ulChar = ulTranslateCharacters(usChar,
|
|
ulFileOffset,
|
|
iWordVersion,
|
|
tOptions.eConversionType,
|
|
tOptions.eEncoding,
|
|
bOldMacFile);
|
|
}
|
|
/* Process character */
|
|
if (ulChar != IGNORE_CHARACTER) {
|
|
switch (ulChar) {
|
|
case PICTURE:
|
|
vStoreString("[pic]", 5, pOutput);
|
|
break;
|
|
case PAR_END:
|
|
case HARD_RETURN:
|
|
case PAGE_BREAK:
|
|
case COLUMN_FEED:
|
|
/* To the next substring */
|
|
pOutput = pStartNextOutput(pOutput);
|
|
vCloseFont();
|
|
pOutput->tFontRef = tOpenFont(0,
|
|
FONT_REGULAR, DEFAULT_FONT_SIZE);
|
|
/* A substring with just one character */
|
|
if (ulChar == HARD_RETURN) {
|
|
vStoreCharacter(HARD_RETURN, pOutput);
|
|
} else {
|
|
vStoreCharacter(PAR_END, pOutput);
|
|
}
|
|
/* To the next substring */
|
|
pOutput = pStartNextOutput(pOutput);
|
|
vCloseFont();
|
|
pOutput->tFontRef = tOpenFont(0,
|
|
FONT_REGULAR, DEFAULT_FONT_SIZE);
|
|
fail(!bCheckDoubleLinkedList(pAnchor));
|
|
break;
|
|
case TABLE_SEPARATOR:
|
|
vStoreCharacter((ULONG)' ', pOutput);
|
|
vStoreCharacter((ULONG)TABLE_SEPARATOR_CHAR,
|
|
pOutput);
|
|
break;
|
|
case TAB:
|
|
vStoreCharacter((ULONG)FILLER_CHAR, pOutput);
|
|
break;
|
|
default:
|
|
vStoreCharacter(ulChar, pOutput);
|
|
break;
|
|
}
|
|
}
|
|
lWidthCurr = lLastStringWidth(pAnchor);
|
|
if (lWidthCurr >= lWidthMax + lRightIndentation) {
|
|
pLeftOver = pSplitList(pAnchor);
|
|
for (pOutput = pAnchor;
|
|
pOutput->pNext != NULL;
|
|
pOutput = pOutput->pNext)
|
|
; /* EMPTY */
|
|
fail(pOutput == NULL);
|
|
/* To the next substring */
|
|
pOutput = pStartNextOutput(pOutput);
|
|
/* A substring with just one HARD_RETURN */
|
|
vStoreCharacter(HARD_RETURN, pOutput);
|
|
/* Put the leftover piece(s) at the end */
|
|
pOutput->pNext = pLeftOver;
|
|
if (pLeftOver != NULL) {
|
|
pLeftOver->pPrev = pOutput;
|
|
}
|
|
fail(!bCheckDoubleLinkedList(pAnchor));
|
|
for (pOutput = pAnchor;
|
|
pOutput->pNext != NULL;
|
|
pOutput = pOutput->pNext)
|
|
; /* EMPTY */
|
|
fail(pOutput == NULL);
|
|
}
|
|
usChar = usNextChar(pFile, hdrftr_list,
|
|
&ulFileOffset, &ulCharPos, NULL);
|
|
}
|
|
vCloseFont();
|
|
if (bOutputContainsText(pAnchor)) {
|
|
return pAnchor;
|
|
}
|
|
pAnchor = pStartNewOutput(pAnchor, NULL);
|
|
pAnchor->szStorage = xfree(pAnchor->szStorage);
|
|
pAnchor = xfree(pAnchor);
|
|
return NULL;
|
|
} /* end of pHdrFtrDecryptor */
|
|
|
|
/*
|
|
* pFootnoteDecryptor - turn a footnote text list element into text
|
|
*/
|
|
char *
|
|
szFootnoteDecryptor(FILE *pFile, ULONG ulCharPosStart, ULONG ulCharPosNext)
|
|
{
|
|
char *szText;
|
|
ULONG ulChar, ulFileOffset, ulCharPos;
|
|
USHORT usChar;
|
|
size_t tLen, tIndex, tNextFree, tStorageSize;
|
|
char szResult[6];
|
|
BOOL bSkip;
|
|
|
|
fail(iWordVersion < 0);
|
|
fail(tOptions.eConversionType == conversion_unknown);
|
|
fail(tOptions.eEncoding == 0);
|
|
|
|
if (ulCharPosStart == ulCharPosNext) {
|
|
/* There are no bytes to decrypt */
|
|
return NULL;
|
|
}
|
|
|
|
if (tOptions.eConversionType != conversion_xml) {
|
|
/* Only implemented for XML output */
|
|
return NULL;
|
|
}
|
|
|
|
bSkip = FALSE;
|
|
|
|
/* Initialise the text buffer */
|
|
tStorageSize = INITIAL_SIZE;
|
|
szText = xmalloc(tStorageSize);
|
|
tNextFree = 0;
|
|
szText[tNextFree] = '\0';
|
|
|
|
/* Goto the start */
|
|
usChar = usToFootnotePosition(pFile, ulCharPosStart);
|
|
ulCharPos = ulCharPosStart;
|
|
ulFileOffset = ulCharPos2FileOffset(ulCharPos);
|
|
/* Skip the unwanted starting characters */
|
|
while (usChar != (USHORT)EOF && ulCharPos != ulCharPosNext &&
|
|
(usChar == FOOTNOTE_OR_ENDNOTE ||
|
|
usChar == PAR_END ||
|
|
usChar == TAB ||
|
|
usChar == (USHORT)' ')) {
|
|
usChar = usNextChar(pFile, footnote_list,
|
|
&ulFileOffset, &ulCharPos, NULL);
|
|
}
|
|
/* Process the footnote text */
|
|
while (usChar != (USHORT)EOF && ulCharPos != ulCharPosNext) {
|
|
/* Skip embedded characters */
|
|
if (usChar == START_EMBEDDED) {
|
|
bSkip = TRUE;
|
|
} else if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
|
|
bSkip = FALSE;
|
|
}
|
|
/* Translate character */
|
|
if (bSkip ||
|
|
usChar == END_IGNORE ||
|
|
usChar == END_EMBEDDED ||
|
|
usChar == FOOTNOTE_OR_ENDNOTE) {
|
|
ulChar = IGNORE_CHARACTER;
|
|
} else {
|
|
ulChar = ulTranslateCharacters(usChar,
|
|
ulFileOffset,
|
|
iWordVersion,
|
|
tOptions.eConversionType,
|
|
tOptions.eEncoding,
|
|
bOldMacFile);
|
|
}
|
|
/* Process character */
|
|
if (ulChar == PICTURE) {
|
|
tLen = 5;
|
|
strcpy(szResult, "[pic]");
|
|
} else if (ulChar == IGNORE_CHARACTER) {
|
|
tLen = 0;
|
|
szResult[0] = '\0';
|
|
} else {
|
|
switch (ulChar) {
|
|
case PAR_END:
|
|
case HARD_RETURN:
|
|
case PAGE_BREAK:
|
|
case COLUMN_FEED:
|
|
ulChar = (ULONG)PAR_END;
|
|
break;
|
|
case TAB:
|
|
ulChar = (ULONG)' ';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
|
|
}
|
|
/* Add the results to the text */
|
|
if (tNextFree + tLen + 1 > tStorageSize) {
|
|
tStorageSize += EXTENTION_SIZE;
|
|
szText = xrealloc(szText, tStorageSize);
|
|
}
|
|
for (tIndex = 0; tIndex < tLen; tIndex++) {
|
|
szText[tNextFree++] = szResult[tIndex];
|
|
}
|
|
szText[tNextFree] = '\0';
|
|
/* Next character */
|
|
usChar = usNextChar(pFile, footnote_list,
|
|
&ulFileOffset, &ulCharPos, NULL);
|
|
}
|
|
/* Remove redundant spaces */
|
|
while (tNextFree != 0 && szText[tNextFree - 1] == ' ') {
|
|
szText[tNextFree - 1] = '\0';
|
|
tNextFree--;
|
|
}
|
|
if (tNextFree == 0) {
|
|
/* No text */
|
|
szText = xfree(szText);
|
|
return NULL;
|
|
}
|
|
return szText;
|
|
} /* end of szFootnoteDecryptor */
|