1f5736e95SDavid du Colombier /*
2f5736e95SDavid du Colombier * wordwin.c
3*25b329d5SDavid du Colombier * Copyright (C) 2002-2005 A.J. van Os; Released under GPL
4f5736e95SDavid du Colombier *
5f5736e95SDavid du Colombier * Description:
6f5736e95SDavid du Colombier * Deal with the WIN internals of a MS Word file
7f5736e95SDavid du Colombier */
8f5736e95SDavid du Colombier
9f5736e95SDavid du Colombier #include "antiword.h"
10f5736e95SDavid du Colombier
11f5736e95SDavid du Colombier
12f5736e95SDavid du Colombier /*
13f5736e95SDavid du Colombier * bGetDocumentText - make a list of the text blocks of a Word document
14f5736e95SDavid du Colombier *
15f5736e95SDavid du Colombier * Return TRUE when succesful, otherwise FALSE
16f5736e95SDavid du Colombier */
17f5736e95SDavid du Colombier static BOOL
bGetDocumentText(FILE * pFile,const UCHAR * aucHeader)18f5736e95SDavid du Colombier bGetDocumentText(FILE *pFile, const UCHAR *aucHeader)
19f5736e95SDavid du Colombier {
20f5736e95SDavid du Colombier text_block_type tTextBlock;
21f5736e95SDavid du Colombier ULONG ulBeginOfText;
22f5736e95SDavid du Colombier ULONG ulTextLen, ulFootnoteLen;
23f5736e95SDavid du Colombier ULONG ulHdrFtrLen, ulMacroLen, ulAnnotationLen;
24f5736e95SDavid du Colombier UINT uiQuickSaves;
25f5736e95SDavid du Colombier USHORT usDocStatus;
26f5736e95SDavid du Colombier BOOL bTemplate, bFastSaved, bEncrypted, bSuccess;
27f5736e95SDavid du Colombier
28f5736e95SDavid du Colombier fail(pFile == NULL);
29f5736e95SDavid du Colombier fail(aucHeader == NULL);
30f5736e95SDavid du Colombier
31f5736e95SDavid du Colombier DBG_MSG("bGetDocumentText");
32f5736e95SDavid du Colombier
33f5736e95SDavid du Colombier /* Get the status flags from the header */
34f5736e95SDavid du Colombier usDocStatus = usGetWord(0x0a, aucHeader);
35f5736e95SDavid du Colombier DBG_HEX(usDocStatus);
36f5736e95SDavid du Colombier bTemplate = (usDocStatus & BIT(0)) != 0;
37f5736e95SDavid du Colombier DBG_MSG_C(bTemplate, "This document is a Template");
38f5736e95SDavid du Colombier bFastSaved = (usDocStatus & BIT(2)) != 0;
39f5736e95SDavid du Colombier uiQuickSaves = (UINT)(usDocStatus & 0x00f0) >> 4;
40f5736e95SDavid du Colombier DBG_MSG_C(bFastSaved, "This document is Fast Saved");
41f5736e95SDavid du Colombier DBG_DEC_C(bFastSaved, uiQuickSaves);
42f5736e95SDavid du Colombier if (bFastSaved) {
43f5736e95SDavid du Colombier werr(0, "Word2: fast saved documents are not supported yet");
44f5736e95SDavid du Colombier return FALSE;
45f5736e95SDavid du Colombier }
46f5736e95SDavid du Colombier bEncrypted = (usDocStatus & BIT(8)) != 0;
47f5736e95SDavid du Colombier if (bEncrypted) {
48f5736e95SDavid du Colombier werr(0, "Encrypted documents are not supported");
49f5736e95SDavid du Colombier return FALSE;
50f5736e95SDavid du Colombier }
51f5736e95SDavid du Colombier
52f5736e95SDavid du Colombier /* Get length information */
53f5736e95SDavid du Colombier ulBeginOfText = ulGetLong(0x18, aucHeader);
54f5736e95SDavid du Colombier DBG_HEX(ulBeginOfText);
55f5736e95SDavid du Colombier ulTextLen = ulGetLong(0x34, aucHeader);
56f5736e95SDavid du Colombier ulFootnoteLen = ulGetLong(0x38, aucHeader);
57f5736e95SDavid du Colombier ulHdrFtrLen = ulGetLong(0x3c, aucHeader);
58f5736e95SDavid du Colombier ulMacroLen = ulGetLong(0x40, aucHeader);
59f5736e95SDavid du Colombier ulAnnotationLen = ulGetLong(0x44, aucHeader);
60f5736e95SDavid du Colombier DBG_DEC(ulTextLen);
61f5736e95SDavid du Colombier DBG_DEC(ulFootnoteLen);
62f5736e95SDavid du Colombier DBG_DEC(ulHdrFtrLen);
63f5736e95SDavid du Colombier DBG_DEC(ulMacroLen);
64f5736e95SDavid du Colombier DBG_DEC(ulAnnotationLen);
65f5736e95SDavid du Colombier if (bFastSaved) {
66f5736e95SDavid du Colombier bSuccess = FALSE;
67f5736e95SDavid du Colombier } else {
68f5736e95SDavid du Colombier tTextBlock.ulFileOffset = ulBeginOfText;
69f5736e95SDavid du Colombier tTextBlock.ulCharPos = ulBeginOfText;
70f5736e95SDavid du Colombier tTextBlock.ulLength = ulTextLen +
71f5736e95SDavid du Colombier ulFootnoteLen +
72f5736e95SDavid du Colombier ulHdrFtrLen + ulMacroLen + ulAnnotationLen;
73f5736e95SDavid du Colombier tTextBlock.bUsesUnicode = FALSE;
74f5736e95SDavid du Colombier tTextBlock.usPropMod = IGNORE_PROPMOD;
75f5736e95SDavid du Colombier bSuccess = bAdd2TextBlockList(&tTextBlock);
76f5736e95SDavid du Colombier DBG_HEX_C(!bSuccess, tTextBlock.ulFileOffset);
77f5736e95SDavid du Colombier DBG_HEX_C(!bSuccess, tTextBlock.ulCharPos);
78f5736e95SDavid du Colombier DBG_DEC_C(!bSuccess, tTextBlock.ulLength);
79f5736e95SDavid du Colombier DBG_DEC_C(!bSuccess, tTextBlock.bUsesUnicode);
80f5736e95SDavid du Colombier DBG_DEC_C(!bSuccess, tTextBlock.usPropMod);
81f5736e95SDavid du Colombier }
82f5736e95SDavid du Colombier
83f5736e95SDavid du Colombier if (bSuccess) {
84f5736e95SDavid du Colombier vSplitBlockList(pFile,
85f5736e95SDavid du Colombier ulTextLen,
86f5736e95SDavid du Colombier ulFootnoteLen,
87f5736e95SDavid du Colombier ulHdrFtrLen,
88f5736e95SDavid du Colombier ulMacroLen,
89f5736e95SDavid du Colombier ulAnnotationLen,
90f5736e95SDavid du Colombier 0,
91f5736e95SDavid du Colombier 0,
92f5736e95SDavid du Colombier 0,
93f5736e95SDavid du Colombier FALSE);
94f5736e95SDavid du Colombier } else {
95f5736e95SDavid du Colombier vDestroyTextBlockList();
96f5736e95SDavid du Colombier werr(0, "I can't find the text of this document");
97f5736e95SDavid du Colombier }
98f5736e95SDavid du Colombier return bSuccess;
99f5736e95SDavid du Colombier } /* end of bGetDocumentText */
100f5736e95SDavid du Colombier
101f5736e95SDavid du Colombier /*
102f5736e95SDavid du Colombier * vGetDocumentData - make a list of the data blocks of a Word document
103f5736e95SDavid du Colombier */
104f5736e95SDavid du Colombier static void
vGetDocumentData(FILE * pFile,const UCHAR * aucHeader)105f5736e95SDavid du Colombier vGetDocumentData(FILE *pFile, const UCHAR *aucHeader)
106f5736e95SDavid du Colombier {
107f5736e95SDavid du Colombier data_block_type tDataBlock;
108f5736e95SDavid du Colombier options_type tOptions;
109f5736e95SDavid du Colombier ULONG ulEndOfText, ulBeginCharInfo;
110f5736e95SDavid du Colombier BOOL bFastSaved, bHasImages, bSuccess;
111f5736e95SDavid du Colombier USHORT usDocStatus;
112f5736e95SDavid du Colombier
113f5736e95SDavid du Colombier /* Get the options */
114f5736e95SDavid du Colombier vGetOptions(&tOptions);
115f5736e95SDavid du Colombier
116f5736e95SDavid du Colombier /* Get the status flags from the header */
117f5736e95SDavid du Colombier usDocStatus = usGetWord(0x0a, aucHeader);
118f5736e95SDavid du Colombier DBG_HEX(usDocStatus);
119f5736e95SDavid du Colombier bFastSaved = (usDocStatus & BIT(2)) != 0;
120f5736e95SDavid du Colombier bHasImages = (usDocStatus & BIT(3)) != 0;
121f5736e95SDavid du Colombier
122f5736e95SDavid du Colombier if (!bHasImages ||
123f5736e95SDavid du Colombier tOptions.eConversionType == conversion_text ||
124*25b329d5SDavid du Colombier tOptions.eConversionType == conversion_fmt_text ||
125f5736e95SDavid du Colombier tOptions.eConversionType == conversion_xml ||
126f5736e95SDavid du Colombier tOptions.eImageLevel == level_no_images) {
127f5736e95SDavid du Colombier /*
128f5736e95SDavid du Colombier * No images in the document or text-only output or
129f5736e95SDavid du Colombier * no images wanted, so no data blocks will be needed
130f5736e95SDavid du Colombier */
131f5736e95SDavid du Colombier vDestroyDataBlockList();
132f5736e95SDavid du Colombier return;
133f5736e95SDavid du Colombier }
134f5736e95SDavid du Colombier
135f5736e95SDavid du Colombier if (bFastSaved) {
136f5736e95SDavid du Colombier bSuccess = FALSE;
137f5736e95SDavid du Colombier } else {
138f5736e95SDavid du Colombier /* This datablock is too big, but it contains all images */
139f5736e95SDavid du Colombier ulEndOfText = ulGetLong(0x1c, aucHeader);
140f5736e95SDavid du Colombier DBG_HEX(ulEndOfText);
141f5736e95SDavid du Colombier ulBeginCharInfo = ulGetLong(0xa0, aucHeader);
142f5736e95SDavid du Colombier DBG_HEX(ulBeginCharInfo);
143f5736e95SDavid du Colombier if (ulBeginCharInfo > ulEndOfText) {
144f5736e95SDavid du Colombier tDataBlock.ulFileOffset = ulEndOfText;
145f5736e95SDavid du Colombier tDataBlock.ulDataPos = ulEndOfText;
146f5736e95SDavid du Colombier tDataBlock.ulLength = ulBeginCharInfo - ulEndOfText;
147f5736e95SDavid du Colombier bSuccess = bAdd2DataBlockList(&tDataBlock);
148f5736e95SDavid du Colombier DBG_HEX_C(!bSuccess, tDataBlock.ulFileOffset);
149f5736e95SDavid du Colombier DBG_HEX_C(!bSuccess, tDataBlock.ulDataPos);
150f5736e95SDavid du Colombier DBG_DEC_C(!bSuccess, tDataBlock.ulLength);
151f5736e95SDavid du Colombier } else {
152f5736e95SDavid du Colombier bSuccess = ulBeginCharInfo == ulEndOfText;
153f5736e95SDavid du Colombier }
154f5736e95SDavid du Colombier }
155f5736e95SDavid du Colombier
156f5736e95SDavid du Colombier if (!bSuccess) {
157f5736e95SDavid du Colombier vDestroyDataBlockList();
158f5736e95SDavid du Colombier werr(0, "I can't find the data of this document");
159f5736e95SDavid du Colombier }
160f5736e95SDavid du Colombier } /* end of vGetDocumentData */
161f5736e95SDavid du Colombier
162f5736e95SDavid du Colombier /*
163f5736e95SDavid du Colombier * iInitDocumentWIN - initialize an WIN document
164f5736e95SDavid du Colombier *
165f5736e95SDavid du Colombier * Returns the version of Word that made the document or -1
166f5736e95SDavid du Colombier */
167f5736e95SDavid du Colombier int
iInitDocumentWIN(FILE * pFile,long lFilesize)168f5736e95SDavid du Colombier iInitDocumentWIN(FILE *pFile, long lFilesize)
169f5736e95SDavid du Colombier {
170f5736e95SDavid du Colombier int iWordVersion;
171f5736e95SDavid du Colombier BOOL bSuccess;
172f5736e95SDavid du Colombier USHORT usIdent;
173f5736e95SDavid du Colombier UCHAR aucHeader[384];
174f5736e95SDavid du Colombier
175f5736e95SDavid du Colombier fail(pFile == NULL);
176f5736e95SDavid du Colombier
177f5736e95SDavid du Colombier if (lFilesize < 384) {
178f5736e95SDavid du Colombier return -1;
179f5736e95SDavid du Colombier }
180f5736e95SDavid du Colombier
181f5736e95SDavid du Colombier /* Read the headerblock */
182f5736e95SDavid du Colombier if (!bReadBytes(aucHeader, 384, 0x00, pFile)) {
183f5736e95SDavid du Colombier return -1;
184f5736e95SDavid du Colombier }
185f5736e95SDavid du Colombier /* Get the "magic number" from the header */
186f5736e95SDavid du Colombier usIdent = usGetWord(0x00, aucHeader);
187f5736e95SDavid du Colombier DBG_HEX(usIdent);
188f5736e95SDavid du Colombier fail(usIdent != 0xa59b && /* WinWord 1.x */
189f5736e95SDavid du Colombier usIdent != 0xa5db); /* WinWord 2.0 */
190f5736e95SDavid du Colombier iWordVersion = iGetVersionNumber(aucHeader);
191f5736e95SDavid du Colombier if (iWordVersion != 1 && iWordVersion != 2) {
192f5736e95SDavid du Colombier werr(0, "This file is not from ''Win Word 1 or 2'.");
193f5736e95SDavid du Colombier return -1;
194f5736e95SDavid du Colombier }
195f5736e95SDavid du Colombier bSuccess = bGetDocumentText(pFile, aucHeader);
196f5736e95SDavid du Colombier if (bSuccess) {
197f5736e95SDavid du Colombier vGetDocumentData(pFile, aucHeader);
198*25b329d5SDavid du Colombier vGetPropertyInfo(pFile, NULL,
199*25b329d5SDavid du Colombier NULL, 0, NULL, 0,
200*25b329d5SDavid du Colombier aucHeader, iWordVersion);
201f5736e95SDavid du Colombier vSetDefaultTabWidth(pFile, NULL,
202f5736e95SDavid du Colombier NULL, 0, NULL, 0,
203f5736e95SDavid du Colombier aucHeader, iWordVersion);
204*25b329d5SDavid du Colombier vGetNotesInfo(pFile, NULL,
205f5736e95SDavid du Colombier NULL, 0, NULL, 0,
206f5736e95SDavid du Colombier aucHeader, iWordVersion);
207f5736e95SDavid du Colombier }
208f5736e95SDavid du Colombier return bSuccess ? iWordVersion : -1;
209f5736e95SDavid du Colombier } /* end of iInitDocumentWIN */
210