1 /*
2  * prop2.c
3  * Copyright (C) 2002-2005 A.J. van Os; Released under GPL
4  *
5  * Description:
6  * Read the property information from a WinWord 1 or 2 file
7  */
8 
9 #include <string.h>
10 #include "antiword.h"
11 
12 
13 #define MAX_FILESIZE		0x2000000UL	/* 32 Mb */
14 
15 /*
16  * iGet2InfoLength - the length of the information for WinWord 1/2 files
17  */
18 static int
iGet2InfoLength(int iByteNbr,const UCHAR * aucGrpprl)19 iGet2InfoLength(int iByteNbr, const UCHAR *aucGrpprl)
20 {
21 	int	iTmp, iDel, iAdd;
22 
23 	switch (ucGetByte(iByteNbr, aucGrpprl)) {
24 	case   3: case  15: case  78: case 152: case 154: case 155:
25 		return 2 + (int)ucGetByte(iByteNbr + 1, aucGrpprl);
26 	case  16: case  17: case  18: case  19: case  21: case  22: case  26:
27 	case  27: case  28: case  30: case  31: case  32: case  33: case  34:
28 	case  35: case  36: case  38: case  39: case  40: case  41: case  42:
29 	case  43: case  45: case  46: case  47: case  48: case  49: case  68:
30 	case  71: case  72: case  82: case  83: case  96: case  97: case  98:
31 	case  99: case 115: case 116: case 119: case 120: case 123: case 124:
32 	case 129: case 130: case 131: case 132: case 135: case 136: case 139:
33 	case 140: case 141: case 142: case 143: case 144: case 145: case 146:
34 	case 147: case 148: case 153: case 159: case 161: case 162:
35 		return 1 + 2;
36 	case  23:
37 		iTmp = (int)ucGetByte(iByteNbr + 1, aucGrpprl);
38 		if (iTmp == 255) {
39 			iDel = (int)ucGetByte(iByteNbr + 2, aucGrpprl);
40 			iAdd = (int)ucGetByte(
41 					iByteNbr + 3 + iDel * 4, aucGrpprl);
42 			iTmp = 2 + iDel * 4 + iAdd * 3;
43 		}
44 		return 2 + iTmp;
45 	case  70:
46 		return 1 + 3;
47 	case  95:
48 		return 1 + 13;
49 	case 157: case 163:
50 		return 1 + 5;
51 	case 158: case 160: case 164:
52 		return 1 + 4;
53 	default:
54 		return 1 + 1;
55 	}
56 } /* end of iGet2InfoLength */
57 
58 /*
59  * Build the lists with Document Property Information for WinWord 1/2 files
60  */
61 void
vGet2DopInfo(FILE * pFile,const UCHAR * aucHeader)62 vGet2DopInfo(FILE *pFile, const UCHAR *aucHeader)
63 {
64 	document_block_type	tDocument;
65 	UCHAR	*aucBuffer;
66 	ULONG	ulBeginDocpInfo, ulTmp;
67 	size_t	tDocpInfoLen;
68 	USHORT	usTmp;
69 
70 	ulBeginDocpInfo = ulGetLong(0x112, aucHeader); /* fcDop */
71 	DBG_HEX(ulBeginDocpInfo);
72 	tDocpInfoLen = (size_t)usGetWord(0x116, aucHeader); /* cbDop */
73 	DBG_DEC(tDocpInfoLen);
74 	if (tDocpInfoLen < 28) {
75 		DBG_MSG("No Document information");
76 		return;
77 	}
78 
79 	aucBuffer = xmalloc(tDocpInfoLen);
80 	if (!bReadBytes(aucBuffer, tDocpInfoLen, ulBeginDocpInfo, pFile)) {
81 		aucBuffer = xfree(aucBuffer);
82 		return;
83 	}
84 
85 	usTmp = usGetWord(0x00, aucBuffer);
86 	tDocument.ucHdrFtrSpecification = (UCHAR)(usTmp >> 8); /* grpfIhdt */
87 	tDocument.usDefaultTabWidth = usGetWord(0x0a, aucBuffer); /* dxaTab */
88 	ulTmp = ulGetLong(0x14, aucBuffer); /* dttmCreated */
89 	tDocument.tCreateDate = tConvertDTTM(ulTmp);
90 	ulTmp = ulGetLong(0x18, aucBuffer); /* dttmRevised */
91 	tDocument.tRevisedDate = tConvertDTTM(ulTmp);
92 	vCreateDocumentInfoList(&tDocument);
93 
94 	aucBuffer = xfree(aucBuffer);
95 } /* end of vGet2DopInfo */
96 
97 /*
98  * Fill the section information block with information
99  * from a WinWord 1/2 file.
100  */
101 static void
vGet2SectionInfo(const UCHAR * aucGrpprl,size_t tBytes,section_block_type * pSection)102 vGet2SectionInfo(const UCHAR *aucGrpprl, size_t tBytes,
103 		section_block_type *pSection)
104 {
105 	int	iFodoOff, iInfoLen;
106 	USHORT	usCcol;
107 	UCHAR	ucTmp;
108 
109 	fail(aucGrpprl == NULL || pSection == NULL);
110 
111 	iFodoOff = 0;
112 	while (tBytes >= (size_t)iFodoOff + 1) {
113 		switch (ucGetByte(iFodoOff, aucGrpprl)) {
114 		case 117:	/* bkc */
115 			ucTmp = ucGetByte(iFodoOff + 1, aucGrpprl);
116 			DBG_DEC(ucTmp);
117 			pSection->bNewPage = ucTmp != 0 && ucTmp != 1;
118 			break;
119 		case 119:	/* ccolM1 */
120 			usCcol = 1 + usGetWord(iFodoOff + 1, aucGrpprl);
121 			DBG_DEC(usCcol);
122 			break;
123 		case 128:	/* grpfIhdt */
124 			pSection->ucHdrFtrSpecification =
125 					ucGetByte(iFodoOff + 1, aucGrpprl);
126 			break;
127 		default:
128 			break;
129 		}
130 		iInfoLen = iGet2InfoLength(iFodoOff, aucGrpprl);
131 		fail(iInfoLen <= 0);
132 		iFodoOff += iInfoLen;
133 	}
134 } /* end of vGet2SectionInfo */
135 
136 /*
137  * Build the lists with Section Property Information for WinWord 1/2 files
138  */
139 void
vGet2SepInfo(FILE * pFile,const UCHAR * aucHeader)140 vGet2SepInfo(FILE *pFile, const UCHAR *aucHeader)
141 {
142 	section_block_type	tSection;
143 	ULONG	*aulSectPage, *aulCharPos;
144 	UCHAR	*aucBuffer, *aucFpage;
145 	ULONG	ulBeginOfText, ulTextOffset, ulBeginSectInfo;
146 	size_t	tSectInfoLen, tIndex, tOffset, tLen, tBytes;
147 	UCHAR	aucTmp[1];
148 
149 	fail(pFile == NULL || aucHeader == NULL);
150 
151 	ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
152 	NO_DBG_HEX(ulBeginOfText);
153 	ulBeginSectInfo = ulGetLong(0x7c, aucHeader); /* fcPlcfsed */
154 	DBG_HEX(ulBeginSectInfo);
155 	tSectInfoLen = (size_t)usGetWord(0x80, aucHeader); /* cbPlcfsed */
156 	DBG_DEC(tSectInfoLen);
157 	if (tSectInfoLen < 4) {
158 		DBG_DEC(tSectInfoLen);
159 		return;
160 	}
161 
162 	aucBuffer = xmalloc(tSectInfoLen);
163 	if (!bReadBytes(aucBuffer, tSectInfoLen, ulBeginSectInfo, pFile)) {
164 		aucBuffer = xfree(aucBuffer);
165 		return;
166 	}
167 	NO_DBG_PRINT_BLOCK(aucBuffer, tSectInfoLen);
168 
169 	/* Read the Section Descriptors */
170 	tLen = (tSectInfoLen - 4) / 10;
171 	/* Save the section offsets */
172 	aulCharPos = xcalloc(tLen, sizeof(ULONG));
173 	for (tIndex = 0, tOffset = 0;
174 	     tIndex < tLen;
175 	     tIndex++, tOffset += 4) {
176 		ulTextOffset = ulGetLong(tOffset, aucBuffer);
177 		NO_DBG_HEX(ulTextOffset);
178 		aulCharPos[tIndex] = ulBeginOfText + ulTextOffset;
179 		NO_DBG_HEX(aulCharPos[tIndex]);
180 	}
181 	/* Save the Sepx offsets */
182 	aulSectPage = xcalloc(tLen, sizeof(ULONG));
183 	for (tIndex = 0, tOffset = (tLen + 1) * 4;
184 	     tIndex < tLen;
185 	     tIndex++, tOffset += 6) {
186 		aulSectPage[tIndex] = ulGetLong(tOffset + 2, aucBuffer);
187 		NO_DBG_HEX(aulSectPage[tIndex]); /* fcSepx */
188 	}
189 	aucBuffer = xfree(aucBuffer);
190 
191 	/* Read the Section Properties */
192 	for (tIndex = 0; tIndex < tLen; tIndex++) {
193 		if (aulSectPage[tIndex] == FC_INVALID) {
194 			vDefault2SectionInfoList(aulCharPos[tIndex]);
195 			continue;
196 		}
197 		/* Get the number of bytes to read */
198 		if (!bReadBytes(aucTmp, 1, aulSectPage[tIndex], pFile)) {
199 			continue;
200 		}
201 		tBytes = 1 + (size_t)ucGetByte(0, aucTmp);
202 		NO_DBG_DEC(tBytes);
203 		/* Read the bytes */
204 		aucFpage = xmalloc(tBytes);
205 		if (!bReadBytes(aucFpage, tBytes, aulSectPage[tIndex], pFile)) {
206 			aucFpage = xfree(aucFpage);
207 			continue;
208 		}
209 		NO_DBG_PRINT_BLOCK(aucFpage, tBytes);
210 		/* Process the bytes */
211 		vGetDefaultSection(&tSection);
212 		vGet2SectionInfo(aucFpage + 1, tBytes - 1, &tSection);
213 		vAdd2SectionInfoList(&tSection, aulCharPos[tIndex]);
214 		aucFpage = xfree(aucFpage);
215 	}
216 	aulCharPos = xfree(aulCharPos);
217 	aulSectPage = xfree(aulSectPage);
218 } /* end of vGet2SepInfo */
219 
220 /*
221  * Build the list with Header/Footer Information for WinWord 1/2 files
222  */
223 void
vGet2HdrFtrInfo(FILE * pFile,const UCHAR * aucHeader)224 vGet2HdrFtrInfo(FILE *pFile, const UCHAR *aucHeader)
225 {
226 	ULONG	*aulCharPos;
227 	UCHAR	*aucBuffer;
228 	ULONG	ulHdrFtrOffset, ulBeginHdrFtrInfo;
229 	size_t	tHdrFtrInfoLen, tIndex, tOffset, tLen;
230 
231 	fail(pFile == NULL || aucHeader == NULL);
232 
233 	ulBeginHdrFtrInfo = ulGetLong(0x9a, aucHeader); /* fcPlcfhdd */
234 	NO_DBG_HEX(ulBeginHdrFtrInfo);
235 	tHdrFtrInfoLen = (size_t)usGetWord(0x9e, aucHeader); /* cbPlcfhdd */
236 	NO_DBG_DEC(tHdrFtrInfoLen);
237 	if (tHdrFtrInfoLen < 8) {
238 		DBG_DEC_C(tHdrFtrInfoLen != 0, tHdrFtrInfoLen);
239 		return;
240 	}
241 
242 	aucBuffer = xmalloc(tHdrFtrInfoLen);
243 	if (!bReadBytes(aucBuffer, tHdrFtrInfoLen, ulBeginHdrFtrInfo, pFile)) {
244 		aucBuffer = xfree(aucBuffer);
245 		return;
246 	}
247 	NO_DBG_PRINT_BLOCK(aucBuffer, tHdrFtrInfoLen);
248 
249 	tLen = tHdrFtrInfoLen / 4 - 1;
250 	/* Save the header/footer offsets */
251 	aulCharPos = xcalloc(tLen, sizeof(ULONG));
252 	for (tIndex = 0, tOffset = 0;
253 	     tIndex < tLen;
254 	     tIndex++, tOffset += 4) {
255 		ulHdrFtrOffset = ulGetLong(tOffset, aucBuffer);
256 		NO_DBG_HEX(ulHdrFtrOffset);
257 		aulCharPos[tIndex] = ulHdrFtrOffset2CharPos(ulHdrFtrOffset);
258 		NO_DBG_HEX(aulCharPos[tIndex]);
259 	}
260 	vCreat2HdrFtrInfoList(aulCharPos, tLen);
261 	aulCharPos = xfree(aulCharPos);
262 	aucBuffer = xfree(aucBuffer);
263 } /* end of vGet2HdrFtrInfo */
264 
265 /*
266  * Translate the rowinfo to a member of the row_info enumeration
267  */
268 row_info_enum
eGet2RowInfo(int iFodo,const UCHAR * aucGrpprl,int iBytes,row_block_type * pRow)269 eGet2RowInfo(int iFodo,
270 	const UCHAR *aucGrpprl, int iBytes, row_block_type *pRow)
271 {
272 	int	iFodoOff, iInfoLen;
273 	int	iIndex, iSize, iCol;
274 	int	iPosCurr, iPosPrev;
275 	USHORT	usTmp;
276 	BOOL	bFound24_0, bFound24_1, bFound25_0, bFound25_1, bFound154;
277 
278 	fail(iFodo < 0 || aucGrpprl == NULL || pRow == NULL);
279 
280 	iFodoOff = 0;
281 	bFound24_0 = FALSE;
282 	bFound24_1 = FALSE;
283 	bFound25_0 = FALSE;
284 	bFound25_1 = FALSE;
285 	bFound154 = FALSE;
286 	while (iBytes >= iFodoOff + 1) {
287 		iInfoLen = 0;
288 		switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
289 		case  24:	/* fIntable */
290 			if (odd(ucGetByte(iFodo + iFodoOff + 1, aucGrpprl))) {
291 				bFound24_1 = TRUE;
292 			} else {
293 				bFound24_0 = TRUE;
294 			}
295 			break;
296 		case  25:	/* fTtp */
297 			if (odd(ucGetByte(iFodo + iFodoOff + 1, aucGrpprl))) {
298 				bFound25_1 = TRUE;
299 			} else {
300 				bFound25_0 = TRUE;
301 			}
302 			break;
303 		case 30:	/* brcTop10 */
304 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
305 			usTmp &= 0x01ff;
306 			NO_DBG_DEC(usTmp >> 6);
307 			if (usTmp == 0) {
308 				pRow->ucBorderInfo &= ~TABLE_BORDER_TOP;
309 			} else {
310 				pRow->ucBorderInfo |= TABLE_BORDER_TOP;
311 			}
312 			break;
313 		case 31:	/* brcLeft10 */
314 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
315 			usTmp &= 0x01ff;
316 			NO_DBG_DEC(usTmp >> 6);
317 			if (usTmp == 0) {
318 				pRow->ucBorderInfo &= ~TABLE_BORDER_LEFT;
319 			} else {
320 				pRow->ucBorderInfo |= TABLE_BORDER_LEFT;
321 			}
322 			break;
323 		case 32:	/* brcBottom10 */
324 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
325 			usTmp &= 0x01ff;
326 			NO_DBG_DEC(usTmp >> 6);
327 			if (usTmp == 0) {
328 				pRow->ucBorderInfo &= ~TABLE_BORDER_BOTTOM;
329 			} else {
330 				pRow->ucBorderInfo |= TABLE_BORDER_BOTTOM;
331 			}
332 			break;
333 		case 33:	/* brcRight10 */
334 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
335 			usTmp &= 0x01ff;
336 			NO_DBG_DEC(usTmp >> 6);
337 			if (usTmp == 0) {
338 				pRow->ucBorderInfo &= ~TABLE_BORDER_RIGHT;
339 			} else {
340 				pRow->ucBorderInfo |= TABLE_BORDER_RIGHT;
341 			}
342 			break;
343 		case 38:	/* brcTop */
344 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
345 			usTmp &= 0x0018;
346 			NO_DBG_DEC(usTmp >> 3);
347 			if (usTmp == 0) {
348 				pRow->ucBorderInfo &= ~TABLE_BORDER_TOP;
349 			} else {
350 				pRow->ucBorderInfo |= TABLE_BORDER_TOP;
351 			}
352 			break;
353 		case 39:	/* brcLeft */
354 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
355 			usTmp &= 0x0018;
356 			NO_DBG_DEC(usTmp >> 3);
357 			if (usTmp == 0) {
358 				pRow->ucBorderInfo &= ~TABLE_BORDER_LEFT;
359 			} else {
360 				pRow->ucBorderInfo |= TABLE_BORDER_LEFT;
361 			}
362 			break;
363 		case 40:	/* brcBottom */
364 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
365 			usTmp &= 0x0018;
366 			NO_DBG_DEC(usTmp >> 3);
367 			if (usTmp == 0) {
368 				pRow->ucBorderInfo &= ~TABLE_BORDER_BOTTOM;
369 			} else {
370 				pRow->ucBorderInfo |= TABLE_BORDER_BOTTOM;
371 			}
372 			break;
373 		case 41:	/* brcRight */
374 			usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
375 			usTmp &= 0x0018;
376 			NO_DBG_DEC(usTmp >> 3);
377 			if (usTmp == 0) {
378 				pRow->ucBorderInfo &= ~TABLE_BORDER_RIGHT;
379 			} else {
380 				pRow->ucBorderInfo |= TABLE_BORDER_RIGHT;
381 			}
382 			break;
383 		case 152:	/* cDefTable10 */
384 		case 154:	/* cDefTable */
385 			iSize = (int)usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
386 			if (iSize < 6 || iBytes < iFodoOff + 7) {
387 				DBG_DEC(iSize);
388 				DBG_DEC(iBytes);
389 				DBG_DEC(iFodoOff);
390 				iInfoLen = 1;
391 				break;
392 			}
393 			iCol = (int)ucGetByte(iFodo + iFodoOff + 3, aucGrpprl);
394 			if (iCol < 1 ||
395 			    iBytes < iFodoOff + 3 + (iCol + 1) * 2) {
396 				DBG_DEC(iCol);
397 				DBG_DEC(iBytes);
398 				DBG_DEC(iFodoOff);
399 				DBG_DEC(ucGetByte(iFodo + iFodoOff, aucGrpprl));
400 				iInfoLen = 1;
401 				break;
402 			}
403 			if (iCol >= (int)elementsof(pRow->asColumnWidth)) {
404 				DBG_DEC(iCol);
405 				werr(1, "The number of columns is corrupt");
406 			}
407 			pRow->ucNumberOfColumns = (UCHAR)iCol;
408 			iPosPrev = (int)(short)usGetWord(
409 					iFodo + iFodoOff + 4,
410 					aucGrpprl);
411 			for (iIndex = 0; iIndex < iCol; iIndex++) {
412 				iPosCurr = (int)(short)usGetWord(
413 					iFodo + iFodoOff + 6 + iIndex * 2,
414 					aucGrpprl);
415 				pRow->asColumnWidth[iIndex] =
416 						(short)(iPosCurr - iPosPrev);
417 				iPosPrev = iPosCurr;
418 			}
419 			bFound154 = TRUE;
420 			break;
421 		default:
422 			break;
423 		}
424 		if (iInfoLen <= 0) {
425 			iInfoLen =
426 				iGet2InfoLength(iFodo + iFodoOff, aucGrpprl);
427 			fail(iInfoLen <= 0);
428 		}
429 		iFodoOff += iInfoLen;
430 	}
431 	if (bFound24_1 && bFound25_1 && bFound154) {
432 		return found_end_of_row;
433 	}
434 	if (bFound24_0 && bFound25_0 && !bFound154) {
435 		return found_not_end_of_row;
436 	}
437 	if (bFound24_1) {
438 		return found_a_cell;
439 	}
440 	if (bFound24_0) {
441 		return found_not_a_cell;
442 	}
443 	return found_nothing;
444 } /* end of eGet2RowInfo */
445 
446 /*
447  * Fill the style information block with information
448  * from a WinWord 1/2 file.
449  */
450 void
vGet2StyleInfo(int iFodo,const UCHAR * aucGrpprl,int iBytes,style_block_type * pStyle)451 vGet2StyleInfo(int iFodo,
452 	const UCHAR *aucGrpprl, int iBytes, style_block_type *pStyle)
453 {
454 	int	iFodoOff, iInfoLen;
455 	int	iTmp, iDel, iAdd;
456 	short	sTmp;
457 	UCHAR	ucTmp;
458 
459 	fail(iFodo < 0 || aucGrpprl == NULL || pStyle == NULL);
460 
461 	NO_DBG_DEC(pStyle->usIstd);
462 
463 	iFodoOff = 0;
464 	while (iBytes >= iFodoOff + 1) {
465 		iInfoLen = 0;
466 		switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
467 		case   2:	/* istd */
468 			sTmp = (short)ucGetByte(
469 					iFodo + iFodoOff + 1, aucGrpprl);
470 			NO_DBG_DEC(sTmp);
471 			break;
472 		case   5:	/* jc */
473 			pStyle->ucAlignment = ucGetByte(
474 					iFodo + iFodoOff + 1, aucGrpprl);
475 			break;
476 		case  12:	/* nfcSeqNumb */
477 			pStyle->ucNFC = ucGetByte(
478 					iFodo + iFodoOff + 1, aucGrpprl);
479 			break;
480 		case  13:	/* nLvlAnm */
481 			ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
482 			pStyle->ucNumLevel = ucTmp;
483 			pStyle->bNumPause =
484 				eGetNumType(ucTmp) == level_type_pause;
485 			break;
486 		case  15:	/* ChgTabsPapx */
487 		case  23:	/* ChgTabs */
488 			iTmp = (int)ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
489 			if (iTmp < 2) {
490 				iInfoLen = 1;
491 				break;
492 			}
493 			NO_DBG_DEC(iTmp);
494 			iDel = (int)ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
495 			if (iTmp < 2 + 2 * iDel) {
496 				iInfoLen = 1;
497 				break;
498 			}
499 			NO_DBG_DEC(iDel);
500 			iAdd = (int)ucGetByte(
501 				iFodo + iFodoOff + 3 + 2 * iDel, aucGrpprl);
502 			if (iTmp < 2 + 2 * iDel + 2 * iAdd) {
503 				iInfoLen = 1;
504 				break;
505 			}
506 			NO_DBG_DEC(iAdd);
507 			break;
508 		case  16:	/* dxaRight */
509 			pStyle->sRightIndent = (short)usGetWord(
510 					iFodo + iFodoOff + 1, aucGrpprl);
511 			NO_DBG_DEC(pStyle->sRightIndent);
512 			break;
513 		case  17:	/* dxaLeft */
514 			pStyle->sLeftIndent = (short)usGetWord(
515 					iFodo + iFodoOff + 1, aucGrpprl);
516 			NO_DBG_DEC(pStyle->sLeftIndent);
517 			break;
518 		case  18:	/* Nest dxaLeft */
519 			sTmp = (short)usGetWord(
520 					iFodo + iFodoOff + 1, aucGrpprl);
521 			pStyle->sLeftIndent += sTmp;
522 			if (pStyle->sLeftIndent < 0) {
523 				pStyle->sLeftIndent = 0;
524 			}
525 			NO_DBG_DEC(sTmp);
526 			NO_DBG_DEC(pStyle->sLeftIndent);
527 			break;
528 		case  19:	/* dxaLeft1 */
529 			pStyle->sLeftIndent1 = (short)usGetWord(
530 					iFodo + iFodoOff + 1, aucGrpprl);
531 			NO_DBG_DEC(pStyle->sLeftIndent1);
532 			break;
533 		case  21:	/* dyaBefore */
534 			pStyle->usBeforeIndent = usGetWord(
535 					iFodo + iFodoOff + 1, aucGrpprl);
536 			NO_DBG_DEC(pStyle->usBeforeIndent);
537 			break;
538 		case  22:	/* dyaAfter */
539 			pStyle->usAfterIndent = usGetWord(
540 					iFodo + iFodoOff + 1, aucGrpprl);
541 			NO_DBG_DEC(pStyle->usAfterIndent);
542 			break;
543 		default:
544 			break;
545 		}
546 		if (iInfoLen <= 0) {
547 			iInfoLen =
548 				iGet2InfoLength(iFodo + iFodoOff, aucGrpprl);
549 			fail(iInfoLen <= 0);
550 		}
551 		iFodoOff += iInfoLen;
552 	}
553 } /* end of vGet2StyleInfo */
554 
555 /*
556  * Build the lists with Paragraph Information for WinWord 1/2 files
557  */
558 void
vGet2PapInfo(FILE * pFile,const UCHAR * aucHeader)559 vGet2PapInfo(FILE *pFile, const UCHAR *aucHeader)
560 {
561 	row_block_type		tRow;
562 	style_block_type	tStyle;
563 	USHORT	*ausParfPage;
564 	UCHAR	*aucBuffer;
565 	ULONG	ulCharPos, ulCharPosFirst, ulCharPosLast;
566 	ULONG	ulBeginParfInfo;
567 	size_t	tParfInfoLen, tParfPageNum, tOffset, tSize, tLenOld, tLen;
568 	int	iIndex, iIndex2, iRun, iFodo, iLen;
569 	row_info_enum	eRowInfo;
570 	USHORT	usParfFirstPage, usCount, usIstd;
571 	UCHAR	ucStc;
572 	UCHAR	aucFpage[BIG_BLOCK_SIZE];
573 
574 	fail(pFile == NULL || aucHeader == NULL);
575 
576 	ulBeginParfInfo = ulGetLong(0xa6, aucHeader); /* fcPlcfbtePapx */
577 	NO_DBG_HEX(ulBeginParfInfo);
578 	tParfInfoLen = (size_t)usGetWord(0xaa, aucHeader); /* cbPlcfbtePapx */
579 	NO_DBG_DEC(tParfInfoLen);
580 	if (tParfInfoLen < 4) {
581 		DBG_DEC(tParfInfoLen);
582 		return;
583 	}
584 
585 	aucBuffer = xmalloc(tParfInfoLen);
586 	if (!bReadBytes(aucBuffer, tParfInfoLen, ulBeginParfInfo, pFile)) {
587 		aucBuffer = xfree(aucBuffer);
588 		return;
589 	}
590 	NO_DBG_PRINT_BLOCK(aucBuffer, tParfInfoLen);
591 
592 	tLen = (tParfInfoLen - 4) / 6;
593 	ausParfPage = xcalloc(tLen, sizeof(USHORT));
594 	for (iIndex = 0, tOffset = (tLen + 1) * 4;
595 	     iIndex < (int)tLen;
596 	     iIndex++, tOffset += 2) {
597 		ausParfPage[iIndex] = usGetWord(tOffset, aucBuffer);
598 		NO_DBG_DEC(ausParfPage[iIndex]);
599 	}
600 	DBG_HEX(ulGetLong(0, aucBuffer));
601 	aucBuffer = xfree(aucBuffer);
602 	tParfPageNum = (size_t)usGetWord(0x144, aucHeader); /* cpnBtePap */
603 	DBG_DEC(tParfPageNum);
604 	if (tLen < tParfPageNum) {
605 		/* Replace ParfPage by a longer version */
606 		tLenOld = tLen;
607 		usParfFirstPage = usGetWord(0x140, aucHeader); /* pnPapFirst */
608 		DBG_DEC(usParfFirstPage);
609 		tLen += tParfPageNum - 1;
610 		tSize = tLen * sizeof(USHORT);
611 		ausParfPage = xrealloc(ausParfPage, tSize);
612 		/* Add new values */
613 		usCount = usParfFirstPage + 1;
614 		for (iIndex = (int)tLenOld; iIndex < (int)tLen; iIndex++) {
615 			ausParfPage[iIndex] = usCount;
616 			NO_DBG_DEC(ausParfPage[iIndex]);
617 			usCount++;
618 		}
619 	}
620 
621 	(void)memset(&tRow, 0, sizeof(tRow));
622 	ulCharPosFirst = CP_INVALID;
623 	for (iIndex = 0; iIndex < (int)tLen; iIndex++) {
624 		if (!bReadBytes(aucFpage, BIG_BLOCK_SIZE,
625 				(ULONG)ausParfPage[iIndex] * BIG_BLOCK_SIZE,
626 				pFile)) {
627 			break;
628 		}
629 		NO_DBG_PRINT_BLOCK(aucFpage, BIG_BLOCK_SIZE);
630 		iRun = (int)ucGetByte(0x1ff, aucFpage);
631 		NO_DBG_DEC(iRun);
632 		for (iIndex2 = 0; iIndex2 < iRun; iIndex2++) {
633 			if ((iRun + 1) * 4 + iIndex2 * 1 >= BIG_BLOCK_SIZE) {
634 				break;
635 			}
636 			NO_DBG_HEX(ulGetLong(iIndex2 * 4, aucFpage));
637 			iFodo = 2 * (int)ucGetByte(
638 				(iRun + 1) * 4 + iIndex2 * 1, aucFpage);
639 			if (iFodo <= 0) {
640 				continue;
641 			}
642 
643 			iLen = 2 * (int)ucGetByte(iFodo, aucFpage);
644 
645 			ucStc = ucGetByte(iFodo + 1, aucFpage);
646 			usIstd = usStc2istd(ucStc);
647 
648 			vFillStyleFromStylesheet(usIstd, &tStyle);
649 			vGet2StyleInfo(iFodo, aucFpage + 8, iLen - 8, &tStyle);
650 			ulCharPos = ulGetLong(iIndex2 * 4, aucFpage);
651 			NO_DBG_HEX(ulCharPos);
652 			tStyle.ulFileOffset = ulCharPos;
653 			vAdd2StyleInfoList(&tStyle);
654 
655 			eRowInfo = eGet2RowInfo(iFodo,
656 					aucFpage + 8, iLen - 8, &tRow);
657 
658 			switch(eRowInfo) {
659 			case found_a_cell:
660 				if (ulCharPosFirst != CP_INVALID) {
661 					break;
662 				}
663 				ulCharPosFirst = ulGetLong(
664 						iIndex2 * 4, aucFpage);
665 				NO_DBG_HEX(ulCharPosFirst);
666 				tRow.ulCharPosStart = ulCharPosFirst;
667 				tRow.ulFileOffsetStart = ulCharPosFirst;
668 				break;
669 			case found_end_of_row:
670 				ulCharPosLast = ulGetLong(
671 						iIndex2 * 4, aucFpage);
672 				NO_DBG_HEX(ulCharPosLast);
673 				tRow.ulCharPosEnd = ulCharPosLast;
674 				/* Add 1 for compatiblity with Word 6 and up */
675 				tRow.ulFileOffsetEnd = ulCharPosLast + 1;
676 				vAdd2RowInfoList(&tRow);
677 				(void)memset(&tRow, 0, sizeof(tRow));
678 				ulCharPosFirst = CP_INVALID;
679 				break;
680 			case found_nothing:
681 				break;
682 			default:
683 				DBG_DEC(eRowInfo);
684 				break;
685 			}
686 		}
687 	}
688 	ausParfPage = xfree(ausParfPage);
689 } /* end of vGet2PapInfo */
690 
691 /*
692  * Fill the font information block with information
693  * from a WinWord 1 file.
694  */
695 void
vGet1FontInfo(int iFodo,const UCHAR * aucGrpprl,size_t tBytes,font_block_type * pFont)696 vGet1FontInfo(int iFodo,
697 	const UCHAR *aucGrpprl, size_t tBytes, font_block_type *pFont)
698 {
699 	BOOL	bIcoChange, bFtcChange, bHpsChange, bKulChange;
700 	USHORT	usTmp;
701 	UCHAR	ucTmp;
702 	UCHAR	aucChpx[12];
703 
704 	fail(iFodo < 0 || aucGrpprl == NULL || pFont == NULL);
705 
706 	if (tBytes > sizeof(aucChpx)) {
707 		NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
708 		return;
709 	}
710 
711 	/* Build the CHPX structure */
712 	(void)memset(aucChpx, 0, sizeof(aucChpx));
713 	(void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
714 
715 	usTmp = usGetWord(0, aucChpx);
716 	if ((usTmp & BIT(0)) != 0) {
717 		pFont->usFontStyle ^= FONT_BOLD;
718 	}
719 	if ((usTmp & BIT(1)) != 0) {
720 		pFont->usFontStyle ^= FONT_ITALIC;
721 	}
722 	if ((usTmp & BIT(2)) != 0) {
723 		pFont->usFontStyle ^= FONT_STRIKE;
724 	}
725 	if ((usTmp & BIT(5)) != 0) {
726 		pFont->usFontStyle ^= FONT_SMALL_CAPITALS;
727 	}
728 	if ((usTmp & BIT(6)) != 0) {
729 		pFont->usFontStyle ^= FONT_CAPITALS;
730 	}
731 	if ((usTmp & BIT(7)) != 0) {
732 		pFont->usFontStyle ^= FONT_HIDDEN;
733 	}
734 
735 	ucTmp = ucGetByte(5, aucChpx);
736 	if (ucTmp != 0) {
737 		if (ucTmp < 128) {
738 			pFont->usFontStyle |= FONT_SUPERSCRIPT;
739 			DBG_MSG("Superscript");
740 		} else {
741 			pFont->usFontStyle |= FONT_SUBSCRIPT;
742 			DBG_MSG("Subscript");
743 		}
744 	}
745 
746 	bIcoChange = (usTmp & BIT(10)) != 0;
747 	bFtcChange = (usTmp & BIT(11)) != 0;
748 	bHpsChange = (usTmp & BIT(12)) != 0;
749 	bKulChange = (usTmp & BIT(13)) != 0;
750 
751 	if (bFtcChange) {
752 		usTmp = usGetWord(2, aucChpx);
753 		if (usTmp <= (USHORT)UCHAR_MAX) {
754 			pFont->ucFontNumber = (UCHAR)usTmp;
755 		} else {
756 			pFont->ucFontNumber = 0;
757 		}
758 	}
759 
760 	if (bHpsChange) {
761 		pFont->usFontSize = (USHORT)ucGetByte(4, aucChpx);
762 	}
763 
764 	if (bIcoChange || bKulChange) {
765 		usTmp = usGetWord(6, aucChpx);
766 		if (bIcoChange) {
767 			pFont->ucFontColor = (UCHAR)((usTmp & 0x0f00) >> 8);
768 			if (pFont->ucFontColor <= 7) {
769 				/* Add 1 for compatibility with Word 2 and up */
770 				pFont->ucFontColor++;
771 			} else {
772 				DBG_DEC(pFont->ucFontColor);
773 				pFont->ucFontColor = 0;
774 			}
775 		}
776 		if (bKulChange) {
777 			usTmp = (usTmp & 0x7000) >> 12;
778 			DBG_DEC_C(usTmp > 4, usTmp);
779 			if (usTmp == 0) {
780 				pFont->usFontStyle &= ~FONT_UNDERLINE;
781 			} else {
782 				pFont->usFontStyle |= FONT_UNDERLINE;
783 			}
784 		}
785 	}
786 } /* end of vGet1FontInfo */
787 
788 /*
789  * Fill the font information block with information
790  * from a WinWord 1/2 file.
791  */
792 void
vGet2FontInfo(int iFodo,const UCHAR * aucGrpprl,size_t tBytes,font_block_type * pFont)793 vGet2FontInfo(int iFodo,
794 	const UCHAR *aucGrpprl, size_t tBytes, font_block_type *pFont)
795 {
796 	BOOL	bIcoChange, bFtcChange, bHpsChange, bKulChange;
797 	USHORT	usTmp;
798 	UCHAR	ucTmp;
799 	UCHAR	aucChpx[18];
800 
801 	fail(iFodo < 0 || aucGrpprl == NULL || pFont == NULL);
802 
803 	if (tBytes > sizeof(aucChpx)) {
804 		NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
805 		return;
806 	}
807 
808 	/* Build the CHPX structure */
809 	(void)memset(aucChpx, 0, sizeof(aucChpx));
810 	(void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
811 
812 	usTmp = usGetWord(0, aucChpx);
813 	if ((usTmp & BIT(0)) != 0) {
814 		pFont->usFontStyle ^= FONT_BOLD;
815 	}
816 	if ((usTmp & BIT(1)) != 0) {
817 		pFont->usFontStyle ^= FONT_ITALIC;
818 	}
819 	if (usTmp & BIT(3)) {
820 		pFont->usFontStyle ^= FONT_MARKDEL;
821 	}
822 	if ((usTmp & BIT(5)) != 0) {
823 		pFont->usFontStyle ^= FONT_SMALL_CAPITALS;
824 	}
825 	if ((usTmp & BIT(6)) != 0) {
826 		pFont->usFontStyle ^= FONT_CAPITALS;
827 	}
828 	if ((usTmp & BIT(7)) != 0) {
829 		pFont->usFontStyle ^= FONT_HIDDEN;
830 	}
831 	if (usTmp & BIT(10)) {
832 		pFont->usFontStyle ^= FONT_STRIKE;
833 	}
834 
835 	ucTmp = ucGetByte(10, aucChpx);
836 	DBG_MSG_C(ucTmp != 0 && ucTmp < 128, "Superscript");
837 	DBG_MSG_C(ucTmp >= 128, "Subscript");
838 
839 	usTmp = usGetWord(2, aucChpx);
840 	if (usTmp == 0) {
841 		/* No changes, nothing to do */
842 		return;
843 	}
844 
845 	bIcoChange = (usTmp & BIT(0)) != 0;
846 	bFtcChange = (usTmp & BIT(1)) != 0;
847 	bHpsChange = (usTmp & BIT(2)) != 0;
848 	bKulChange = (usTmp & BIT(3)) != 0;
849 
850 	if (bFtcChange) {
851 		usTmp = usGetWord(4, aucChpx);
852 		if (usTmp <= (USHORT)UCHAR_MAX) {
853 			pFont->ucFontNumber = (UCHAR)usTmp;
854 		} else {
855 			pFont->ucFontNumber = 0;
856 		}
857 	}
858 
859 	if (bHpsChange) {
860 		pFont->usFontSize = usGetWord(6, aucChpx);
861 	}
862 
863 	if (bIcoChange || bKulChange) {
864 		ucTmp = ucGetByte(9, aucChpx);
865 		if (bIcoChange) {
866 			pFont->ucFontColor = ucTmp & 0x1f;
867 			if (pFont->ucFontColor > 16) {
868 				DBG_DEC(pFont->ucFontColor);
869 				pFont->ucFontColor = 0;
870 			}
871 		}
872 		if (bKulChange) {
873 			ucTmp = (ucTmp & 0xe0) >> 5;
874 			DBG_DEC_C(ucTmp > 4, ucTmp);
875 			if (ucTmp == 0) {
876 				pFont->usFontStyle &= ~FONT_UNDERLINE;
877 			} else {
878 				pFont->usFontStyle |= FONT_UNDERLINE;
879 			}
880 		}
881 	}
882 } /* end of vGet2FontInfo */
883 
884 /*
885  * Fill the picture information block with information from a WinWord 1 file.
886  * Returns TRUE when successful, otherwise FALSE
887  */
888 static BOOL
bGet1PicInfo(int iFodo,const UCHAR * aucGrpprl,size_t tBytes,picture_block_type * pPicture)889 bGet1PicInfo(int iFodo,
890 	const UCHAR *aucGrpprl, size_t tBytes, picture_block_type *pPicture)
891 {
892 	ULONG	ulTmp;
893 	UCHAR	aucChpx[12];
894 
895 	fail(iFodo < 0 || aucGrpprl == NULL || pPicture == NULL);
896 
897 	if (tBytes > sizeof(aucChpx)) {
898 		NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
899 		tBytes = sizeof(aucChpx);
900 	}
901 
902 	/* Build the CHPX structure */
903 	(void)memset(aucChpx, 0, sizeof(aucChpx));
904 	(void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
905 
906 	ulTmp = ulGetLong(8, aucChpx);
907 	if (ulTmp != 0 && ulTmp < MAX_FILESIZE) {
908 		pPicture->ulPictureOffset = ulTmp;
909 		DBG_HEX(pPicture->ulPictureOffset);
910 		return TRUE;
911 	}
912 	return FALSE;
913 } /* end of bGet1PicInfo */
914 
915 /*
916  * Fill the picture information block with information from a WinWord 2 file.
917  * Returns TRUE when successful, otherwise FALSE
918  */
919 static BOOL
bGet2PicInfo(int iFodo,const UCHAR * aucGrpprl,size_t tBytes,picture_block_type * pPicture)920 bGet2PicInfo(int iFodo,
921 	const UCHAR *aucGrpprl, size_t tBytes, picture_block_type *pPicture)
922 {
923 	ULONG	ulTmp;
924 	UCHAR	aucChpx[18];
925 
926 	fail(iFodo < 0 || aucGrpprl == NULL || pPicture == NULL);
927 
928 	if (tBytes > sizeof(aucChpx)) {
929 		NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
930 		tBytes = sizeof(aucChpx);
931 	}
932 
933 	/* Build the CHPX structure */
934 	(void)memset(aucChpx, 0, sizeof(aucChpx));
935 	(void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
936 
937 	ulTmp = ulGetLong(14, aucChpx);
938 	if (ulTmp != 0 && ulTmp < MAX_FILESIZE) {
939 		pPicture->ulPictureOffset = ulTmp;
940 		DBG_HEX(pPicture->ulPictureOffset);
941 		DBG_DEC(tBytes);
942 		return TRUE;
943 	}
944 	return FALSE;
945 } /* end of bGet2PicInfo */
946 
947 /*
948  * Build the lists with Character Information for WinWord 1/2 files
949  */
950 void
vGet2ChrInfo(FILE * pFile,int iWordVersion,const UCHAR * aucHeader)951 vGet2ChrInfo(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
952 {
953 	font_block_type		tFont;
954 	picture_block_type	tPicture;
955 	USHORT	*ausCharPage;
956 	UCHAR	*aucBuffer;
957 	ULONG	ulFileOffset, ulCharPos, ulBeginCharInfo;
958 	size_t	tCharInfoLen, tOffset, tSize, tChrLen, tCharPageNum;
959 	size_t	tLenOld, tLen;
960 	int	iIndex, iIndex2, iRun, iFodo;
961 	BOOL	bSuccess1, bSuccess2;
962 	USHORT	usCharFirstPage, usCount, usIstd;
963 	UCHAR	aucFpage[BIG_BLOCK_SIZE];
964 
965 	fail(pFile == NULL || aucHeader == NULL);
966 	fail(iWordVersion != 1 && iWordVersion != 2);
967 
968 	ulBeginCharInfo = ulGetLong(0xa0, aucHeader); /* fcPlcfbteChpx */
969 	DBG_HEX(ulBeginCharInfo);
970 	tCharInfoLen = (size_t)usGetWord(0xa4, aucHeader); /* cbPlcfbteChpx */
971 	DBG_DEC(tCharInfoLen);
972 	if (tCharInfoLen < 4) {
973 		DBG_DEC(tCharInfoLen);
974 		return;
975 	}
976 
977 	aucBuffer = xmalloc(tCharInfoLen);
978 	if (!bReadBytes(aucBuffer, tCharInfoLen, ulBeginCharInfo, pFile)) {
979 		aucBuffer = xfree(aucBuffer);
980 		return;
981 	}
982 	NO_DBG_PRINT_BLOCK(aucBuffer, tCharInfoLen);
983 
984 	tLen = (tCharInfoLen - 4) / 6;
985 	ausCharPage = xcalloc(tLen, sizeof(USHORT));
986 	for (iIndex = 0, tOffset = (tLen + 1) * 4;
987 	     iIndex < (int)tLen;
988 	     iIndex++, tOffset += 2) {
989 		ausCharPage[iIndex] = usGetWord(tOffset, aucBuffer);
990 		NO_DBG_DEC(ausCharPage[iIndex]);
991 	}
992 	DBG_HEX(ulGetLong(0, aucBuffer));
993 	aucBuffer = xfree(aucBuffer);
994 	tCharPageNum = (size_t)usGetWord(0x142, aucHeader); /* cpnBteChp */
995 	DBG_DEC(tCharPageNum);
996 	if (tLen < tCharPageNum) {
997 		/* Replace CharPage by a longer version */
998 		tLenOld = tLen;
999 		usCharFirstPage = usGetWord(0x13e, aucHeader); /* pnChrFirst */
1000 		NO_DBG_DEC(usCharFirstPage);
1001 		tLen += tCharPageNum - 1;
1002 		tSize = tLen * sizeof(USHORT);
1003 		ausCharPage = xrealloc(ausCharPage, tSize);
1004 		/* Add new values */
1005 		usCount = usCharFirstPage + 1;
1006 		for (iIndex = (int)tLenOld; iIndex < (int)tLen; iIndex++) {
1007 			ausCharPage[iIndex] = usCount;
1008 			NO_DBG_DEC(ausCharPage[iIndex]);
1009 			usCount++;
1010 		}
1011 	}
1012 
1013 	for (iIndex = 0; iIndex < (int)tLen; iIndex++) {
1014 		if (!bReadBytes(aucFpage, BIG_BLOCK_SIZE,
1015 				(ULONG)ausCharPage[iIndex] * BIG_BLOCK_SIZE,
1016 				pFile)) {
1017 			break;
1018 		}
1019 		NO_DBG_PRINT_BLOCK(aucFpage, BIG_BLOCK_SIZE);
1020 		iRun = (int)ucGetByte(0x1ff, aucFpage);
1021 		NO_DBG_DEC(iRun);
1022 		for (iIndex2 = 0; iIndex2 < iRun; iIndex2++) {
1023 			if ((iRun + 1) * 4 + iIndex2 >= BIG_BLOCK_SIZE) {
1024 				break;
1025 			}
1026 			ulCharPos = ulGetLong(iIndex2 * 4, aucFpage);
1027 			ulFileOffset = ulCharPos;
1028 			iFodo = 2 * (int)ucGetByte(
1029 				(iRun + 1) * 4 + iIndex2, aucFpage);
1030 
1031 			tChrLen = (size_t)ucGetByte(iFodo, aucFpage);
1032 
1033 			usIstd = usGetIstd(ulFileOffset);
1034 			vFillFontFromStylesheet(usIstd, &tFont);
1035 			if (iFodo != 0) {
1036 				if (iWordVersion == 1) {
1037 					vGet1FontInfo(iFodo,
1038 						aucFpage + 1, tChrLen, &tFont);
1039 				} else if (iWordVersion == 2) {
1040 					vGet2FontInfo(iFodo,
1041 						aucFpage + 1, tChrLen, &tFont);
1042 				}
1043 			}
1044 			tFont.ulFileOffset = ulFileOffset;
1045 			vAdd2FontInfoList(&tFont);
1046 
1047 			if (iFodo <= 0) {
1048 				continue;
1049 			}
1050 
1051 			(void)memset(&tPicture, 0, sizeof(tPicture));
1052 			bSuccess1 = iWordVersion == 1 &&
1053 					bGet1PicInfo(iFodo, aucFpage + 1,
1054 						tChrLen, &tPicture);
1055 			bSuccess2 = iWordVersion == 2 &&
1056 					bGet2PicInfo(iFodo, aucFpage + 1,
1057 						tChrLen, &tPicture);
1058 			if (bSuccess1 || bSuccess2) {
1059 				tPicture.ulFileOffset = ulFileOffset;
1060 				tPicture.ulFileOffsetPicture =
1061 						tPicture.ulPictureOffset;
1062 				vAdd2PictInfoList(&tPicture);
1063 			}
1064 		}
1065 	}
1066 	ausCharPage = xfree(ausCharPage);
1067 } /* end of vGet2ChrInfo */
1068