xref: /plan9/sys/src/cmd/aux/antiword/wordwin.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
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