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