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