xref: /plan9/sys/src/cmd/aux/antiword/findtext.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1f5736e95SDavid du Colombier /*
2f5736e95SDavid du Colombier  * findtext.c
3*25b329d5SDavid du Colombier  * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
4f5736e95SDavid du Colombier  *
5f5736e95SDavid du Colombier  * Description:
6f5736e95SDavid du Colombier  * Find the blocks that contain the text of MS Word files
7f5736e95SDavid du Colombier  */
8f5736e95SDavid du Colombier 
9f5736e95SDavid du Colombier #include <stdio.h>
10f5736e95SDavid du Colombier #include <stdlib.h>
11f5736e95SDavid du Colombier #include "antiword.h"
12f5736e95SDavid du Colombier 
13f5736e95SDavid du Colombier 
14f5736e95SDavid du Colombier /*
15f5736e95SDavid du Colombier  * bAddTextBlocks - Add the blocks to the text block list
16f5736e95SDavid du Colombier  *
17f5736e95SDavid du Colombier  * Returns TRUE when successful, FALSE if not
18f5736e95SDavid du Colombier  */
19f5736e95SDavid du Colombier BOOL
bAddTextBlocks(ULONG ulCharPosFirst,ULONG ulTotalLength,BOOL bUsesUnicode,USHORT usPropMod,ULONG ulStartBlock,const ULONG * aulBBD,size_t tBBDLen)20f5736e95SDavid du Colombier bAddTextBlocks(ULONG ulCharPosFirst, ULONG ulTotalLength,
21f5736e95SDavid du Colombier 	BOOL bUsesUnicode, USHORT usPropMod,
22f5736e95SDavid du Colombier 	ULONG ulStartBlock, const ULONG *aulBBD, size_t tBBDLen)
23f5736e95SDavid du Colombier {
24f5736e95SDavid du Colombier 	text_block_type	tTextBlock;
25f5736e95SDavid du Colombier 	ULONG	ulCharPos, ulOffset, ulIndex;
26f5736e95SDavid du Colombier 	long	lToGo;
27f5736e95SDavid du Colombier 
28f5736e95SDavid du Colombier 	fail(ulTotalLength > (ULONG)LONG_MAX / 2);
29f5736e95SDavid du Colombier 	fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
30f5736e95SDavid du Colombier 	fail(aulBBD == NULL);
31f5736e95SDavid du Colombier 
32f5736e95SDavid du Colombier 	NO_DBG_HEX(ulCharPosFirst);
33f5736e95SDavid du Colombier 	NO_DBG_DEC(ulTotalLength);
34f5736e95SDavid du Colombier 
35f5736e95SDavid du Colombier 	if (bUsesUnicode) {
36f5736e95SDavid du Colombier 		/* One character equals two bytes */
37f5736e95SDavid du Colombier 		NO_DBG_MSG("Uses Unicode");
38f5736e95SDavid du Colombier 		lToGo = (long)ulTotalLength * 2;
39f5736e95SDavid du Colombier 	} else {
40f5736e95SDavid du Colombier 		/* One character equals one byte */
41f5736e95SDavid du Colombier 		NO_DBG_MSG("Uses ASCII");
42f5736e95SDavid du Colombier 		lToGo = (long)ulTotalLength;
43f5736e95SDavid du Colombier 	}
44f5736e95SDavid du Colombier 
45f5736e95SDavid du Colombier 	ulCharPos = ulCharPosFirst;
46f5736e95SDavid du Colombier 	ulOffset = ulCharPosFirst;
47f5736e95SDavid du Colombier 	for (ulIndex = ulStartBlock;
48f5736e95SDavid du Colombier 	     ulIndex != END_OF_CHAIN && lToGo > 0;
49f5736e95SDavid du Colombier 	     ulIndex = aulBBD[ulIndex]) {
50f5736e95SDavid du Colombier 		if (ulIndex >= (ULONG)tBBDLen) {
51f5736e95SDavid du Colombier 			DBG_DEC(ulIndex);
52f5736e95SDavid du Colombier 			DBG_DEC(tBBDLen);
53f5736e95SDavid du Colombier 			werr(1, "The Big Block Depot is damaged");
54f5736e95SDavid du Colombier 		}
55f5736e95SDavid du Colombier 		if (ulOffset >= BIG_BLOCK_SIZE) {
56f5736e95SDavid du Colombier 			ulOffset -= BIG_BLOCK_SIZE;
57f5736e95SDavid du Colombier 			continue;
58f5736e95SDavid du Colombier 		}
59f5736e95SDavid du Colombier 		tTextBlock.ulFileOffset =
60f5736e95SDavid du Colombier 			(ulIndex + 1) * BIG_BLOCK_SIZE + ulOffset;
61f5736e95SDavid du Colombier 		tTextBlock.ulCharPos = ulCharPos;
62f5736e95SDavid du Colombier 		tTextBlock.ulLength = min(BIG_BLOCK_SIZE - ulOffset,
63f5736e95SDavid du Colombier 						(ULONG)lToGo);
64f5736e95SDavid du Colombier 		tTextBlock.bUsesUnicode = bUsesUnicode;
65f5736e95SDavid du Colombier 		tTextBlock.usPropMod = usPropMod;
66f5736e95SDavid du Colombier 		ulOffset = 0;
67f5736e95SDavid du Colombier 		if (!bAdd2TextBlockList(&tTextBlock)) {
68f5736e95SDavid du Colombier 			DBG_HEX(tTextBlock.ulFileOffset);
69f5736e95SDavid du Colombier 			DBG_HEX(tTextBlock.ulCharPos);
70f5736e95SDavid du Colombier 			DBG_DEC(tTextBlock.ulLength);
71f5736e95SDavid du Colombier 			DBG_DEC(tTextBlock.bUsesUnicode);
72f5736e95SDavid du Colombier 			DBG_DEC(tTextBlock.usPropMod);
73f5736e95SDavid du Colombier 			return FALSE;
74f5736e95SDavid du Colombier 		}
75f5736e95SDavid du Colombier 		ulCharPos += tTextBlock.ulLength;
76f5736e95SDavid du Colombier 		lToGo -= (long)tTextBlock.ulLength;
77f5736e95SDavid du Colombier 	}
78f5736e95SDavid du Colombier 	DBG_DEC_C(lToGo != 0, lToGo);
79f5736e95SDavid du Colombier 	return lToGo == 0;
80f5736e95SDavid du Colombier } /* end of bAddTextBlocks */
81f5736e95SDavid du Colombier 
82f5736e95SDavid du Colombier /*
83f5736e95SDavid du Colombier  * bGet6DocumentText - make a list of the text blocks of Word 6/7 files
84f5736e95SDavid du Colombier  *
85f5736e95SDavid du Colombier  * Code for "fast saved" files.
86f5736e95SDavid du Colombier  *
87f5736e95SDavid du Colombier  * Returns TRUE when successful, FALSE if not
88f5736e95SDavid du Colombier  */
89f5736e95SDavid du Colombier BOOL
bGet6DocumentText(FILE * pFile,BOOL bUsesUnicode,ULONG ulStartBlock,const ULONG * aulBBD,size_t tBBDLen,const UCHAR * aucHeader)90f5736e95SDavid du Colombier bGet6DocumentText(FILE *pFile, BOOL bUsesUnicode, ULONG ulStartBlock,
91f5736e95SDavid du Colombier 	const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
92f5736e95SDavid du Colombier {
93f5736e95SDavid du Colombier 	UCHAR	*aucBuffer;
94f5736e95SDavid du Colombier 	ULONG	ulBeginTextInfo, ulTextOffset, ulTotLength;
95f5736e95SDavid du Colombier 	size_t	tTextInfoLen;
96f5736e95SDavid du Colombier 	int	iIndex, iType, iOff, iLen, iPieces;
97f5736e95SDavid du Colombier 	USHORT	usPropMod;
98f5736e95SDavid du Colombier 
99f5736e95SDavid du Colombier 	DBG_MSG("bGet6DocumentText");
100f5736e95SDavid du Colombier 
101f5736e95SDavid du Colombier 	fail(pFile == NULL);
102f5736e95SDavid du Colombier 	fail(aulBBD == NULL);
103f5736e95SDavid du Colombier 	fail(aucHeader == NULL);
104f5736e95SDavid du Colombier 
105f5736e95SDavid du Colombier 	ulBeginTextInfo = ulGetLong(0x160, aucHeader);	/* fcClx */
106f5736e95SDavid du Colombier 	DBG_HEX(ulBeginTextInfo);
107f5736e95SDavid du Colombier 	tTextInfoLen = (size_t)ulGetLong(0x164, aucHeader);	/* lcbClx */
108f5736e95SDavid du Colombier 	DBG_DEC(tTextInfoLen);
109f5736e95SDavid du Colombier 
110f5736e95SDavid du Colombier 	aucBuffer = xmalloc(tTextInfoLen);
111f5736e95SDavid du Colombier 	if (!bReadBuffer(pFile, ulStartBlock,
112f5736e95SDavid du Colombier 			aulBBD, tBBDLen, BIG_BLOCK_SIZE,
113f5736e95SDavid du Colombier 			aucBuffer, ulBeginTextInfo, tTextInfoLen)) {
114f5736e95SDavid du Colombier 		aucBuffer = xfree(aucBuffer);
115f5736e95SDavid du Colombier 		return FALSE;
116f5736e95SDavid du Colombier 	}
117f5736e95SDavid du Colombier 	NO_DBG_PRINT_BLOCK(aucBuffer, tTextInfoLen);
118f5736e95SDavid du Colombier 
119f5736e95SDavid du Colombier 	iOff = 0;
120f5736e95SDavid du Colombier 	while ((size_t)iOff < tTextInfoLen) {
121f5736e95SDavid du Colombier 		iType = (int)ucGetByte(iOff, aucBuffer);
122f5736e95SDavid du Colombier 		iOff++;
123f5736e95SDavid du Colombier 		if (iType == 0) {
124f5736e95SDavid du Colombier 			DBG_FIXME();
125f5736e95SDavid du Colombier 			iOff++;
126f5736e95SDavid du Colombier 			continue;
127f5736e95SDavid du Colombier 		}
128f5736e95SDavid du Colombier 		if (iType == 1) {
129f5736e95SDavid du Colombier 			iLen = (int)usGetWord(iOff, aucBuffer);
130f5736e95SDavid du Colombier 			vAdd2PropModList(aucBuffer + iOff);
131f5736e95SDavid du Colombier 			iOff += iLen + 2;
132f5736e95SDavid du Colombier 			continue;
133f5736e95SDavid du Colombier 		}
134f5736e95SDavid du Colombier 		if (iType != 2) {
135f5736e95SDavid du Colombier 			werr(0, "Unknown type of 'fastsaved' format");
136f5736e95SDavid du Colombier 			aucBuffer = xfree(aucBuffer);
137f5736e95SDavid du Colombier 			return FALSE;
138f5736e95SDavid du Colombier 		}
139f5736e95SDavid du Colombier 		/* Type 2 */
140f5736e95SDavid du Colombier 		iLen = (int)usGetWord(iOff, aucBuffer);
141f5736e95SDavid du Colombier 		NO_DBG_DEC(iLen);
142f5736e95SDavid du Colombier 		iOff += 4;
143f5736e95SDavid du Colombier 		iPieces = (iLen - 4) / 12;
144f5736e95SDavid du Colombier 		DBG_DEC(iPieces);
145f5736e95SDavid du Colombier 		for (iIndex = 0; iIndex < iPieces; iIndex++) {
146f5736e95SDavid du Colombier 			ulTextOffset = ulGetLong(
147f5736e95SDavid du Colombier 				iOff + (iPieces + 1) * 4 + iIndex * 8 + 2,
148f5736e95SDavid du Colombier 				aucBuffer);
149f5736e95SDavid du Colombier 			usPropMod = usGetWord(
150f5736e95SDavid du Colombier 				iOff + (iPieces + 1) * 4 + iIndex * 8 + 6,
151f5736e95SDavid du Colombier 				aucBuffer);
152f5736e95SDavid du Colombier 			ulTotLength = ulGetLong(iOff + (iIndex + 1) * 4,
153f5736e95SDavid du Colombier 						aucBuffer) -
154f5736e95SDavid du Colombier 					ulGetLong(iOff + iIndex * 4,
155f5736e95SDavid du Colombier 						aucBuffer);
156f5736e95SDavid du Colombier 			NO_DBG_HEX_C(usPropMod != 0, usPropMod);
157f5736e95SDavid du Colombier 			if (!bAddTextBlocks(ulTextOffset, ulTotLength,
158f5736e95SDavid du Colombier 					bUsesUnicode, usPropMod,
159f5736e95SDavid du Colombier 					ulStartBlock,
160f5736e95SDavid du Colombier 					aulBBD, tBBDLen)) {
161f5736e95SDavid du Colombier 				aucBuffer = xfree(aucBuffer);
162f5736e95SDavid du Colombier 				return FALSE;
163f5736e95SDavid du Colombier 			}
164f5736e95SDavid du Colombier 		}
165f5736e95SDavid du Colombier 		break;
166f5736e95SDavid du Colombier 	}
167f5736e95SDavid du Colombier 	aucBuffer = xfree(aucBuffer);
168f5736e95SDavid du Colombier 	return TRUE;
169f5736e95SDavid du Colombier } /* end of bGet6DocumentText */
170f5736e95SDavid du Colombier 
171f5736e95SDavid du Colombier /*
172f5736e95SDavid du Colombier  * bGet8DocumentText - make a list of the text blocks of Word 8/97 files
173f5736e95SDavid du Colombier  *
174f5736e95SDavid du Colombier  * Returns TRUE when successful, FALSE if not
175f5736e95SDavid du Colombier  */
176f5736e95SDavid du Colombier BOOL
bGet8DocumentText(FILE * pFile,const pps_info_type * pPPS,const ULONG * aulBBD,size_t tBBDLen,const ULONG * aulSBD,size_t tSBDLen,const UCHAR * aucHeader)177f5736e95SDavid du Colombier bGet8DocumentText(FILE *pFile, const pps_info_type *pPPS,
178f5736e95SDavid du Colombier 	const ULONG *aulBBD, size_t tBBDLen,
179f5736e95SDavid du Colombier 	const ULONG *aulSBD, size_t tSBDLen,
180f5736e95SDavid du Colombier 	const UCHAR *aucHeader)
181f5736e95SDavid du Colombier {
182f5736e95SDavid du Colombier 	const ULONG	*aulBlockDepot;
183f5736e95SDavid du Colombier 	UCHAR	*aucBuffer;
184f5736e95SDavid du Colombier 	ULONG	ulTextOffset, ulBeginTextInfo;
185f5736e95SDavid du Colombier 	ULONG	ulTotLength, ulLen;
186f5736e95SDavid du Colombier 	long	lIndex, lPieces, lOff;
187f5736e95SDavid du Colombier 	size_t	tTextInfoLen, tBlockDepotLen, tBlockSize;
188f5736e95SDavid du Colombier 	int	iType, iLen;
189f5736e95SDavid du Colombier 	BOOL	bUsesUnicode;
190*25b329d5SDavid du Colombier 	USHORT	usPropMod;
191f5736e95SDavid du Colombier 
192f5736e95SDavid du Colombier 	DBG_MSG("bGet8DocumentText");
193f5736e95SDavid du Colombier 
194f5736e95SDavid du Colombier 	fail(pFile == NULL || pPPS == NULL);
195f5736e95SDavid du Colombier 	fail(aulBBD == NULL || aulSBD == NULL);
196f5736e95SDavid du Colombier 	fail(aucHeader == NULL);
197f5736e95SDavid du Colombier 
198f5736e95SDavid du Colombier   	ulBeginTextInfo = ulGetLong(0x1a2, aucHeader);	/* fcClx */
199f5736e95SDavid du Colombier 	DBG_HEX(ulBeginTextInfo);
200f5736e95SDavid du Colombier 	tTextInfoLen = (size_t)ulGetLong(0x1a6, aucHeader);	/* lcbClx */
201f5736e95SDavid du Colombier 	DBG_DEC(tTextInfoLen);
202f5736e95SDavid du Colombier 
203*25b329d5SDavid du Colombier 	DBG_DEC(pPPS->tTable.ulSB);
204*25b329d5SDavid du Colombier 	DBG_HEX(pPPS->tTable.ulSize);
205*25b329d5SDavid du Colombier 	if (pPPS->tTable.ulSize == 0) {
206f5736e95SDavid du Colombier 		return FALSE;
207f5736e95SDavid du Colombier 	}
208*25b329d5SDavid du Colombier 
209*25b329d5SDavid du Colombier 	if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
210f5736e95SDavid du Colombier 	  	/* Use the Small Block Depot */
211f5736e95SDavid du Colombier 		aulBlockDepot = aulSBD;
212f5736e95SDavid du Colombier 		tBlockDepotLen = tSBDLen;
213f5736e95SDavid du Colombier 		tBlockSize = SMALL_BLOCK_SIZE;
214f5736e95SDavid du Colombier 	} else {
215f5736e95SDavid du Colombier 	  	/* Use the Big Block Depot */
216f5736e95SDavid du Colombier 		aulBlockDepot = aulBBD;
217f5736e95SDavid du Colombier 		tBlockDepotLen = tBBDLen;
218f5736e95SDavid du Colombier 		tBlockSize = BIG_BLOCK_SIZE;
219f5736e95SDavid du Colombier 	}
220f5736e95SDavid du Colombier 	aucBuffer = xmalloc(tTextInfoLen);
221*25b329d5SDavid du Colombier 	if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
222f5736e95SDavid du Colombier 			aulBlockDepot, tBlockDepotLen, tBlockSize,
223f5736e95SDavid du Colombier 			aucBuffer, ulBeginTextInfo, tTextInfoLen)) {
224f5736e95SDavid du Colombier 		aucBuffer = xfree(aucBuffer);
225f5736e95SDavid du Colombier 		return FALSE;
226f5736e95SDavid du Colombier 	}
227f5736e95SDavid du Colombier 	NO_DBG_PRINT_BLOCK(aucBuffer, tTextInfoLen);
228f5736e95SDavid du Colombier 
229f5736e95SDavid du Colombier 	lOff = 0;
230f5736e95SDavid du Colombier 	while (lOff < (long)tTextInfoLen) {
231f5736e95SDavid du Colombier 		iType = (int)ucGetByte(lOff, aucBuffer);
232f5736e95SDavid du Colombier 		lOff++;
233f5736e95SDavid du Colombier 		if (iType == 0) {
234f5736e95SDavid du Colombier 			DBG_FIXME();
235f5736e95SDavid du Colombier 			lOff++;
236f5736e95SDavid du Colombier 			continue;
237f5736e95SDavid du Colombier 		}
238f5736e95SDavid du Colombier 		if (iType == 1) {
239f5736e95SDavid du Colombier 			iLen = (int)usGetWord(lOff, aucBuffer);
240f5736e95SDavid du Colombier 			vAdd2PropModList(aucBuffer + lOff);
241f5736e95SDavid du Colombier 			lOff += (long)iLen + 2;
242f5736e95SDavid du Colombier 			continue;
243f5736e95SDavid du Colombier 		}
244f5736e95SDavid du Colombier 		if (iType != 2) {
245f5736e95SDavid du Colombier 			werr(0, "Unknown type of 'fastsaved' format");
246f5736e95SDavid du Colombier 			aucBuffer = xfree(aucBuffer);
247f5736e95SDavid du Colombier 			return FALSE;
248f5736e95SDavid du Colombier 		}
249f5736e95SDavid du Colombier 		/* Type 2 */
250f5736e95SDavid du Colombier 		ulLen = ulGetLong(lOff, aucBuffer);
251f5736e95SDavid du Colombier 		if (ulLen < 4) {
252f5736e95SDavid du Colombier 			DBG_DEC(ulLen);
253f5736e95SDavid du Colombier 			return FALSE;
254f5736e95SDavid du Colombier 		}
255f5736e95SDavid du Colombier 		lOff += 4;
256f5736e95SDavid du Colombier 		lPieces = (long)((ulLen - 4) / 12);
257f5736e95SDavid du Colombier 		DBG_DEC(lPieces);
258f5736e95SDavid du Colombier 		for (lIndex = 0; lIndex < lPieces; lIndex++) {
259f5736e95SDavid du Colombier 			ulTextOffset = ulGetLong(
260f5736e95SDavid du Colombier 				lOff + (lPieces + 1) * 4 + lIndex * 8 + 2,
261f5736e95SDavid du Colombier 				aucBuffer);
262f5736e95SDavid du Colombier 			usPropMod = usGetWord(
263f5736e95SDavid du Colombier 				lOff + (lPieces + 1) * 4 + lIndex * 8 + 6,
264f5736e95SDavid du Colombier 				aucBuffer);
265f5736e95SDavid du Colombier 			ulTotLength = ulGetLong(lOff + (lIndex + 1) * 4,
266f5736e95SDavid du Colombier 						aucBuffer) -
267f5736e95SDavid du Colombier 					ulGetLong(lOff + lIndex * 4,
268f5736e95SDavid du Colombier 						aucBuffer);
269f5736e95SDavid du Colombier 			if ((ulTextOffset & BIT(30)) == 0) {
270f5736e95SDavid du Colombier 				bUsesUnicode = TRUE;
271f5736e95SDavid du Colombier 			} else {
272f5736e95SDavid du Colombier 				bUsesUnicode = FALSE;
273f5736e95SDavid du Colombier 				ulTextOffset &= ~BIT(30);
274f5736e95SDavid du Colombier 				ulTextOffset /= 2;
275f5736e95SDavid du Colombier 			}
276f5736e95SDavid du Colombier 			NO_DBG_HEX_C(usPropMod != 0, usPropMod);
277f5736e95SDavid du Colombier 			if (!bAddTextBlocks(ulTextOffset, ulTotLength,
278f5736e95SDavid du Colombier 					bUsesUnicode, usPropMod,
279f5736e95SDavid du Colombier 					pPPS->tWordDocument.ulSB,
280f5736e95SDavid du Colombier 					aulBBD, tBBDLen)) {
281f5736e95SDavid du Colombier 				aucBuffer = xfree(aucBuffer);
282f5736e95SDavid du Colombier 				return FALSE;
283f5736e95SDavid du Colombier 			}
284f5736e95SDavid du Colombier 		}
285f5736e95SDavid du Colombier 		break;
286f5736e95SDavid du Colombier 	}
287f5736e95SDavid du Colombier 	aucBuffer = xfree(aucBuffer);
288f5736e95SDavid du Colombier 	return TRUE;
289f5736e95SDavid du Colombier } /* end of bGet8DocumentText */
290