xref: /plan9/sys/src/cmd/aux/antiword/stylesheet.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * stylesheet.c
3  * Copyright (C) 2001-2004 A.J. van Os; Released under GNU GPL
4  *
5  * Description:
6  * Build, read and destroy a list of stylesheet information
7  *
8  */
9 
10 #include <string.h>
11 #include "antiword.h"
12 
13 
14 #define SGC_PAP		1
15 #define SGC_CHP		2
16 
17 /* Variables needed to describe the stylesheet list */
18 static style_block_type	*atStyleInfo = NULL;
19 static font_block_type	*atFontInfo = NULL;
20 static BOOL		*abFilled = NULL;
21 static size_t		tStdCount = 0;
22 
23 
24 /*
25  * vDestroyStylesheetList - destroy the stylesheet list
26  */
27 void
vDestroyStylesheetList(void)28 vDestroyStylesheetList(void)
29 {
30 	DBG_MSG("vDestroyStylesheetList");
31 
32 	tStdCount = 0;
33 	atStyleInfo = xfree(atStyleInfo);
34 	atFontInfo = xfree(atFontInfo);
35 	abFilled = xfree(abFilled);
36 } /* end of vDestroyStylesheetList */
37 
38 /*
39  * vGetDefaultStyle - fill the style struct with default values
40  */
41 static void
vGetDefaultStyle(style_block_type * pStyle)42 vGetDefaultStyle(style_block_type *pStyle)
43 {
44 	(void)memset(pStyle, 0, sizeof(*pStyle));
45 	pStyle->usIstd = ISTD_INVALID;
46 	pStyle->usIstdNext = ISTD_INVALID;
47 	pStyle->usStartAt = 1;
48 	pStyle->ucListLevel = 9;
49 } /* end of vGetDefaultStyle */
50 
51 /*
52  * vGetDefaultFont - fill the font struct with default values
53  */
54 static void
vGetDefaultFont(font_block_type * pFont,USHORT usDefaultFontNumber)55 vGetDefaultFont(font_block_type *pFont, USHORT usDefaultFontNumber)
56 {
57 	(void)memset(pFont, 0, sizeof(*pFont));
58 	pFont->usFontSize = DEFAULT_FONT_SIZE;
59 	if (usDefaultFontNumber <= (USHORT)UCHAR_MAX) {
60 		pFont->ucFontNumber = (UCHAR)usDefaultFontNumber;
61 	} else {
62 		DBG_DEC(usDefaultFontNumber);
63 		DBG_FIXME();
64 		pFont->ucFontNumber = 0;
65 	}
66 } /* end of vGetDefaultFont */
67 
68 /*
69  * iGetStyleIndex - get the index of the record with the specified istd
70  *
71  * returns the index when found, otherwise -1
72  */
73 static int
iGetStyleIndex(USHORT usIstd)74 iGetStyleIndex(USHORT usIstd)
75 {
76 	int	iIndex;
77 
78 	fail(abFilled == NULL);
79 
80 	if (usIstd == ISTD_INVALID || abFilled == NULL) {
81 		return -1;
82 	}
83 
84 	for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
85 		if (abFilled[iIndex] && atStyleInfo[iIndex].usIstd == usIstd) {
86 			/* The record is filled and the istd matches */
87 			return iIndex;
88 		}
89 	}
90 	return -1;
91 } /* end of iGetStyleIndex */
92 
93 /*
94  * Get a build-in style for Winword 1/2
95  */
96 static void
vGetBuildinStyle(UCHAR ucStc,style_block_type * pStyle)97 vGetBuildinStyle(UCHAR ucStc, style_block_type *pStyle)
98 {
99 	fail(pStyle == NULL);
100 
101 	/* Start with de defaults */
102 	vGetDefaultStyle(pStyle);
103 
104 	/* Add the build-in style info */
105 	switch (ucStc) {
106 	case 246:
107 	case 247:
108 	case 248:
109 	case 249:
110 	case 250:
111 	case 255:
112 		pStyle->sLeftIndent = 720;
113 		break;
114 	case 251:
115 	case 252:
116 		pStyle->sLeftIndent = 360;
117 		break;
118 	case 253:
119 		pStyle->usBeforeIndent = 120;
120 		break;
121 	case 254:
122 		pStyle->usBeforeIndent = 240;
123 		break;
124 	default:
125 		if (ucStc >= 233 && ucStc <= 239) {
126 			pStyle->sLeftIndent = (239 - (short)ucStc) * 360;
127 		}
128 		if (ucStc >= 225 && ucStc <= 232) {
129 			pStyle->sLeftIndent = (232 - (short)ucStc) * 720;
130 			pStyle->sRightIndent = 720;
131 		}
132 		break;
133 	}
134 } /* end of vGetBuildinStyle */
135 
136 /*
137  * Get a build-in fontstyle for Winword 1/2
138  */
139 static void
vGetBuildinFont(UCHAR ucStc,font_block_type * pFont)140 vGetBuildinFont(UCHAR ucStc, font_block_type *pFont)
141 {
142 	fail(pFont == NULL);
143 
144 	/* Start with de defaults */
145 	vGetDefaultFont(pFont, 0);
146 
147 	/* Add the build-in fontstyle info */
148 	switch (ucStc) {
149 	case 223:
150 	case 244:
151 		pFont->usFontSize = 16;
152 		break;
153 	case 246:
154 	case 247:
155 	case 248:
156 		pFont->usFontStyle |= FONT_ITALIC;
157 		break;
158 	case 249:
159 		pFont->usFontStyle |= FONT_UNDERLINE;
160 		break;
161 	case 250:
162 		pFont->usFontStyle |= FONT_BOLD;
163 		break;
164 	case 251:
165 		pFont->usFontStyle |= FONT_UNDERLINE;
166 		pFont->usFontSize = 24;
167 		break;
168 	case 252:
169 		pFont->usFontStyle |= FONT_BOLD;
170 		pFont->usFontSize = 24;
171 		break;
172 	case 253:
173 		pFont->ucFontNumber = 2;
174 		pFont->usFontStyle |= FONT_BOLD;
175 		pFont->usFontSize = 24;
176 		break;
177 	case 254:
178 		pFont->ucFontNumber = 2;
179 		pFont->usFontStyle |= (FONT_BOLD|FONT_UNDERLINE);
180 		pFont->usFontSize = 24;
181 		break;
182 	default:
183 		break;
184 	}
185 } /* end of vGetBuildinFont */
186 
187 /*
188  * Convert a stylecode (stc) as used by WinWord 1/2 into a styleindex (istd)
189  * as used by Word 6 and up
190  */
191 USHORT
usStc2istd(UCHAR ucStc)192 usStc2istd(UCHAR ucStc)
193 {
194 	/* Old nil style to new nil style */
195 	if (ucStc == 222) {
196 		return STI_NIL;
197 	}
198 
199 	/* Heading 1 through 9 must become istd 1 through 9 */
200 	/* so 254 through 246 must become 1 through 9 and vice versa */
201 	if ((ucStc >= 1 && ucStc <= 9) ||
202 	    (ucStc >= 246 && ucStc <= 254)) {
203 		return 255 - (USHORT)ucStc;
204 	}
205 	return (USHORT)ucStc;
206 } /* end of usStd2istd */
207 
208 /*
209  * Build the lists with Stylesheet Information for WinWord 1/2 files
210  */
211 void
vGet2Stylesheet(FILE * pFile,int iWordVersion,const UCHAR * aucHeader)212 vGet2Stylesheet(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
213 {
214 	style_block_type	*pStyle;
215 	font_block_type		*pFont;
216 	UCHAR	*aucBuffer;
217 	ULONG	ulBeginStshInfo;
218 	size_t	tStshInfoLen, tName, tChpx, tPapx, tMaxIndex;
219 	int	iStIndex, iChpxIndex, iPapxIndex, iSt, iChpx, iPapx;
220 	int	iStd, iIndex, iBaseStyleIndex, iCounter;
221 	USHORT	usBaseStyle;
222 	UCHAR	ucStc, ucStcNext, ucStcBase;
223 
224 	fail(pFile == NULL || aucHeader == NULL);
225 	fail(iWordVersion != 1 && iWordVersion != 2);
226 
227 	ulBeginStshInfo = ulGetLong(0x5e, aucHeader); /* fcStshf */
228 	NO_DBG_HEX(ulBeginStshInfo);
229 	tStshInfoLen = (size_t)usGetWord(0x62, aucHeader); /* cbStshf */
230 	NO_DBG_DEC(tStshInfoLen);
231 
232 	aucBuffer = xmalloc(tStshInfoLen);
233 	if (!bReadBytes(aucBuffer, tStshInfoLen, ulBeginStshInfo, pFile)) {
234 		aucBuffer = xfree(aucBuffer);
235 		return;
236 	}
237 	NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
238 
239 	fail(2 > tStshInfoLen);
240 	iStd = (int)usGetWord(0, aucBuffer);
241 
242 	fail(2 + 2 > tStshInfoLen);
243 	tName = (size_t)usGetWord(2, aucBuffer);
244 
245 	fail(2 + tName + 2 > tStshInfoLen);
246 	tChpx = (size_t)usGetWord(2 + tName, aucBuffer);
247 
248 	fail(2 + tName + tChpx + 2 > tStshInfoLen);
249 	tPapx = (size_t)usGetWord(2 + tName + tChpx, aucBuffer);
250 
251 	fail(2 + tName + tChpx + tPapx + 2 > tStshInfoLen);
252 	tStdCount = (size_t)usGetWord(2 + tName + tChpx + tPapx, aucBuffer);
253 
254 	NO_DBG_HEX(tStdCount);
255 
256 	atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
257 	atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
258 	abFilled = xcalloc(tStdCount, sizeof(BOOL));
259 
260 	do {
261 		iCounter = 0;
262 		iStIndex = 2 + 2;
263 		iChpxIndex = 2 + (int)tName + 2;
264 		iPapxIndex = 2 + (int)tName + (int)tChpx + 2;
265 		tMaxIndex = 2 + tName + tChpx + tPapx + 2;
266 		/* Read the styles one-by-one */
267 		for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
268 			pStyle = &atStyleInfo[iIndex];
269 			pFont = &atFontInfo[iIndex];
270 			iSt = (int)ucGetByte(iStIndex, aucBuffer);
271 			iChpx = (int)ucGetByte(iChpxIndex, aucBuffer);
272 			iPapx = (int)ucGetByte(iPapxIndex, aucBuffer);
273 			NO_DBG_HEX(iSt);
274 			NO_DBG_HEX(iChpx);
275 			NO_DBG_HEX(iPapx);
276 			if (iSt == 0xff || tMaxIndex + 1 >= tStshInfoLen) {
277 				/* Undefined style or no information */
278 				iStIndex++;
279 				iChpxIndex++;
280 				iPapxIndex++;
281 				tMaxIndex += 2;
282 				if (!abFilled[iIndex]) {
283 					DBG_HEX_C(iChpx != 0xff, iChpx);
284 					DBG_HEX_C(iPapx != 0xff, iPapx);
285 					vGetDefaultStyle(pStyle);
286 					vGetDefaultFont(pFont, 0);
287 					abFilled[iIndex] = TRUE;
288 				}
289 				continue;
290 			}
291 
292 			NO_DBG_STRN(aucBuffer + iStIndex + 1, iSt);
293 			iStIndex += iSt + 1;
294 
295 			ucStcNext = ucGetByte(tMaxIndex, aucBuffer);
296 			ucStcBase = ucGetByte(tMaxIndex + 1, aucBuffer);
297 			ucStc = (UCHAR)((iIndex - iStd) & 0xff);
298 			NO_DBG_DEC(ucStc);
299 
300 			if (iChpx == 0xff || iPapx == 0xff) {
301 				/* Use a build-in style */
302 				iChpxIndex++;
303 				iPapxIndex++;
304 				tMaxIndex += 2;
305 				if (!abFilled[iIndex]) {
306 					DBG_HEX_C(iChpx != 0xff, iChpx);
307 					DBG_HEX_C(iPapx != 0xff, iPapx);
308 					vGetBuildinStyle(ucStc, pStyle);
309 					pStyle->usIstd = usStc2istd(ucStc);
310 					pStyle->usIstdNext =
311 							usStc2istd(ucStcNext);
312 					vGetBuildinFont(ucStc, pFont);
313 					abFilled[iIndex] = TRUE;
314 				}
315 				continue;
316 			}
317 
318 			if (abFilled[iIndex]) {
319 				/* This record has already been filled */
320 				iChpxIndex += iChpx + 1;
321 				iPapxIndex += iPapx + 1;
322 				tMaxIndex += 2;
323 				continue;
324 			}
325 
326 			usBaseStyle = usStc2istd(ucStcBase);
327 
328 			if (usBaseStyle == STI_NIL) {
329 				/* Based on the Nil style */
330 				vGetDefaultStyle(pStyle);
331 				vGetDefaultFont(pFont, 0);
332 			} else {
333 				iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
334 				NO_DBG_DEC(iBaseStyleIndex);
335 				if (iBaseStyleIndex < 0) {
336 					/* This style is not known yet */
337 					iChpxIndex += iChpx + 1;
338 					iPapxIndex += iPapx + 1;
339 					tMaxIndex += 2;
340 					continue;
341 				}
342 				fail(iBaseStyleIndex >= (int)tStdCount);
343 				fail(!abFilled[iBaseStyleIndex]);
344 				/* Based on the specified base style */
345 				*pStyle = atStyleInfo[iBaseStyleIndex];
346 				*pFont = atFontInfo[iBaseStyleIndex];
347 			}
348 			pStyle->usIstd = usStc2istd(ucStc);
349 			pStyle->usIstdNext = usStc2istd(ucStcNext);
350 
351 			abFilled[iIndex] = TRUE;
352 			iCounter++;
353 
354 			/* Add the changes if any */
355 			switch (iChpx) {
356 			case 0x00:
357 			case 0xff:
358 				iChpxIndex++;
359 				break;
360 			default:
361 				NO_DBG_PRINT_BLOCK(aucBuffer + iChpxIndex + 1,
362 						iChpx);
363 				if (iWordVersion == 1) {
364 					vGet1FontInfo(0,
365 						aucBuffer + iChpxIndex + 1,
366 						(size_t)iChpx, pFont);
367 				} else {
368 					vGet2FontInfo(0,
369 						aucBuffer + iChpxIndex + 1,
370 						(size_t)iChpx, pFont);
371 				}
372 				iChpxIndex += iChpx + 1;
373 				break;
374 			}
375 
376 			switch (iPapx) {
377 			case 0x00:
378 			case 0xff:
379 				iPapxIndex++;
380 				break;
381 			default:
382 				NO_DBG_PRINT_BLOCK(aucBuffer + iPapxIndex + 8,
383 						iPapx - 7);
384 				vGet2StyleInfo(0, aucBuffer + iPapxIndex + 8,
385 						iPapx - 7, pStyle);
386 				iPapxIndex += iPapx + 1;
387 				break;
388 			}
389 			tMaxIndex += 2;
390 
391 		}
392 		NO_DBG_DEC(iCounter);
393 	} while (iCounter > 0);
394 
395 	/* Fill records that are still empty */
396 	for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
397 		if (!abFilled[iIndex]) {
398 			NO_DBG_DEC(iIndex);
399 			vGetDefaultStyle(&atStyleInfo[iIndex]);
400 			vGetDefaultFont(&atFontInfo[iIndex], 0);
401 		}
402 	}
403 
404 	/* Clean up before you leave */
405 	abFilled = xfree(abFilled);
406 	aucBuffer = xfree(aucBuffer);
407 } /* end of vGet2Stylesheet */
408 
409 /*
410  * Build the lists with Stylesheet Information for Word 6/7 files
411  */
412 void
vGet6Stylesheet(FILE * pFile,ULONG ulStartBlock,const ULONG * aulBBD,size_t tBBDLen,const UCHAR * aucHeader)413 vGet6Stylesheet(FILE *pFile, ULONG ulStartBlock,
414 	const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
415 {
416 	style_block_type	*pStyle;
417 	font_block_type		*pFont;
418 	UCHAR	*aucBuffer;
419 	ULONG	ulBeginStshInfo;
420 	size_t	tStshInfoLen, tOffset, tStdLen, tStdBaseInFile;
421 	size_t	tPos, tNameLen, tUpxLen;
422 	int	iIndex, iBaseStyleIndex, iCounter;
423 	USHORT	usTmp, usUpxCount, usStyleType, usBaseStyle;
424 	USHORT	usFtcStandardChpStsh;
425 
426 	fail(pFile == NULL || aucHeader == NULL);
427 	fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
428 	fail(aulBBD == NULL);
429 
430 	ulBeginStshInfo = ulGetLong(0x60, aucHeader); /* fcStshf */
431 	NO_DBG_HEX(ulBeginStshInfo);
432 	tStshInfoLen = (size_t)ulGetLong(0x64, aucHeader); /* lcbStshf */
433 	NO_DBG_DEC(tStshInfoLen);
434 
435 	aucBuffer = xmalloc(tStshInfoLen);
436 	if (!bReadBuffer(pFile, ulStartBlock,
437 			aulBBD, tBBDLen, BIG_BLOCK_SIZE,
438 			aucBuffer, ulBeginStshInfo, tStshInfoLen)) {
439 		aucBuffer = xfree(aucBuffer);
440 		return;
441 	}
442 	NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
443 
444 	tStdCount = (size_t)usGetWord(2, aucBuffer);
445 	NO_DBG_DEC(tStdCount);
446 	tStdBaseInFile = (size_t)usGetWord(4, aucBuffer);
447 	usFtcStandardChpStsh = usGetWord(14, aucBuffer);
448 	NO_DBG_DEC(usFtcStandardChpStsh);
449 
450 	atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
451 	atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
452 	abFilled = xcalloc(tStdCount, sizeof(BOOL));
453 
454 	do {
455 		iCounter = 0;
456 		/* Read the styles one-by-one */
457 		for (iIndex = 0, tOffset = 2 + (size_t)usGetWord(0, aucBuffer);
458 		     iIndex < (int)tStdCount;
459 		     iIndex++, tOffset += 2 + tStdLen) {
460 			NO_DBG_DEC(tOffset);
461 			tStdLen = (size_t)usGetWord(tOffset, aucBuffer);
462 			NO_DBG_DEC(tStdLen);
463 			if (abFilled[iIndex]) {
464 				/* This record has already been filled */
465 				continue;
466 			}
467 			pStyle = &atStyleInfo[iIndex];
468 			pFont = &atFontInfo[iIndex];
469 			if (tStdLen == 0) {
470 				/* Empty record */
471 				vGetDefaultStyle(pStyle);
472 				vGetDefaultFont(pFont, usFtcStandardChpStsh);
473 				abFilled[iIndex] = TRUE;
474 				continue;
475 			}
476 			usTmp = usGetWord(tOffset + 4, aucBuffer);
477 			usStyleType = usTmp % 16;
478 			usBaseStyle = usTmp / 16;
479 			NO_DBG_DEC(usStyleType);
480 			NO_DBG_DEC(usBaseStyle);
481 			if (usBaseStyle == STI_NIL || usBaseStyle == STI_USER) {
482 				/* Based on the Nil style */
483 				vGetDefaultStyle(pStyle);
484 				vGetDefaultFont(pFont, usFtcStandardChpStsh);
485 			} else {
486 				iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
487 				NO_DBG_DEC(iBaseStyleIndex);
488 				if (iBaseStyleIndex < 0) {
489 					/* This base style is not known yet */
490 					continue;
491 				}
492 				fail(iBaseStyleIndex >= (int)tStdCount);
493 				fail(!abFilled[iBaseStyleIndex]);
494 				/* Based on the specified base style */
495 				*pStyle = atStyleInfo[iBaseStyleIndex];
496 				pStyle->usIstd = ISTD_INVALID;
497 				*pFont = atFontInfo[iBaseStyleIndex];
498 			}
499 			abFilled[iIndex] = TRUE;
500 			iCounter++;
501 			/* STD */
502 			usTmp = usGetWord(tOffset + 6, aucBuffer);
503 			usUpxCount = usTmp % 16;
504 			pStyle->usIstdNext = usTmp / 16;;
505 			NO_DBG_DEC(usUpxCount);
506 			tPos = 2 + tStdBaseInFile;
507 			NO_DBG_DEC(tPos);
508 			tNameLen = (size_t)ucGetByte(tOffset + tPos, aucBuffer);
509 			NO_DBG_DEC(tNameLen);
510 			NO_DBG_STRN(aucBuffer + tOffset + tPos + 1, tNameLen);
511 			tNameLen++;	/* Include the ASCII NULL character */
512 			tPos += 1 + tNameLen;
513 			if (odd(tPos)) {
514 				tPos++;
515 			}
516 			NO_DBG_DEC(tPos);
517 			if (tPos >= tStdLen) {
518 				continue;
519 			}
520 			tUpxLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
521 			NO_DBG_DEC(tUpxLen);
522 			if (tPos + tUpxLen > tStdLen) {
523 				/* UPX length too large to be a record */
524 				DBG_DEC_C(tPos + tUpxLen > tStdLen,
525 						tPos + tUpxLen);
526 				continue;
527 			}
528 			if (usStyleType == SGC_PAP && usUpxCount >= 1) {
529 				if (tUpxLen >= 2) {
530 					NO_DBG_PRINT_BLOCK(
531 						aucBuffer + tOffset + tPos + 2,
532 						tUpxLen);
533 					pStyle->usIstd = usGetWord(
534 						tOffset + tPos + 2, aucBuffer);
535 					NO_DBG_DEC(pStyle->usIstd);
536 					NO_DBG_DEC(pStyle->usIstdNext);
537 					vGet6StyleInfo(0,
538 						aucBuffer + tOffset + tPos + 4,
539 						tUpxLen - 2, pStyle);
540 					NO_DBG_DEC(pStyle->sLeftIndent);
541 					NO_DBG_DEC(pStyle->sRightIndent);
542 					NO_DBG_HEX(pStyle->ucAlignment);
543 				}
544 				tPos += 2 + tUpxLen;
545 				if (odd(tPos)) {
546 					tPos++;
547 				}
548 				NO_DBG_DEC(tPos);
549 				tUpxLen = (size_t)usGetWord(
550 						tOffset + tPos, aucBuffer);
551 				NO_DBG_DEC(tUpxLen);
552 			}
553 			if (tUpxLen == 0 || tPos + tUpxLen > tStdLen) {
554 				/* Too small or too large to be a record */
555 				DBG_DEC_C(tPos + tUpxLen > tStdLen,
556 							tPos + tUpxLen);
557 				continue;
558 			}
559 			if ((usStyleType == SGC_PAP && usUpxCount >= 2) ||
560 			    (usStyleType == SGC_CHP && usUpxCount >= 1)) {
561 				NO_DBG_PRINT_BLOCK(
562 						aucBuffer + tOffset + tPos + 2,
563 						tUpxLen);
564 				vGet6FontInfo(0, ISTD_INVALID,
565 						aucBuffer + tOffset + tPos + 2,
566 						(int)tUpxLen, pFont);
567 				NO_DBG_DEC(pFont->usFontSize);
568 				NO_DBG_DEC(pFont->ucFontcolor);
569 				NO_DBG_HEX(pFont->usFontStyle);
570 			}
571 		}
572 		NO_DBG_DEC(iCounter);
573 	} while (iCounter > 0);
574 
575 	/* Fill records that are still empty */
576 	for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
577 		if (!abFilled[iIndex]) {
578 			NO_DBG_DEC(iIndex);
579 			vGetDefaultStyle(&atStyleInfo[iIndex]);
580 			vGetDefaultFont(&atFontInfo[iIndex],
581 					usFtcStandardChpStsh);
582 		}
583 	}
584 
585 	/* Clean up before you leave */
586 	abFilled = xfree(abFilled);
587 	aucBuffer = xfree(aucBuffer);
588 } /* end of vGet6Stylesheet */
589 
590 /*
591  * Build the lists with Stylesheet Information for Word 8/9/10 files
592  */
593 void
vGet8Stylesheet(FILE * pFile,const pps_info_type * pPPS,const ULONG * aulBBD,size_t tBBDLen,const ULONG * aulSBD,size_t tSBDLen,const UCHAR * aucHeader)594 vGet8Stylesheet(FILE *pFile, const pps_info_type *pPPS,
595 	const ULONG *aulBBD, size_t tBBDLen,
596 	const ULONG *aulSBD, size_t tSBDLen,
597 	const UCHAR *aucHeader)
598 {
599 	style_block_type	*pStyle;
600 	font_block_type		*pFont;
601 	const ULONG	*aulBlockDepot;
602 	UCHAR	*aucBuffer;
603 	ULONG	ulBeginStshInfo;
604 	size_t	tStshInfoLen, tBlockDepotLen, tOffset, tStdLen, tStdBaseInFile;
605 	size_t	tBlockSize, tPos, tNameLen, tUpxLen;
606 	int	iIndex, iBaseStyleIndex, iCounter;
607 	USHORT	usTmp, usUpxCount, usStyleType, usBaseStyle;
608 	USHORT	usFtcStandardChpStsh;
609 
610 	fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
611 	fail(aulBBD == NULL || aulSBD == NULL);
612 
613 	ulBeginStshInfo = ulGetLong(0xa2, aucHeader); /* fcStshf */
614 	NO_DBG_HEX(ulBeginStshInfo);
615 	tStshInfoLen = (size_t)ulGetLong(0xa6, aucHeader); /* lcbStshf */
616 	NO_DBG_DEC(tStshInfoLen);
617 
618 	NO_DBG_DEC(pPPS->tTable.ulSB);
619 	NO_DBG_HEX(pPPS->tTable.ulSize);
620 	if (pPPS->tTable.ulSize == 0) {
621 		DBG_MSG("No stylesheet information");
622 		return;
623 	}
624 
625 	if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
626 		/* Use the Small Block Depot */
627 		aulBlockDepot = aulSBD;
628 		tBlockDepotLen = tSBDLen;
629 		tBlockSize = SMALL_BLOCK_SIZE;
630 	} else {
631 		/* Use the Big Block Depot */
632 		aulBlockDepot = aulBBD;
633 		tBlockDepotLen = tBBDLen;
634 		tBlockSize = BIG_BLOCK_SIZE;
635 	}
636 	aucBuffer = xmalloc(tStshInfoLen);
637 	if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
638 			aulBlockDepot, tBlockDepotLen, tBlockSize,
639 			aucBuffer, ulBeginStshInfo, tStshInfoLen)) {
640 		aucBuffer = xfree(aucBuffer);
641 		return;
642 	}
643 	NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
644 
645 	tStdCount = (size_t)usGetWord(2, aucBuffer);
646 	NO_DBG_DEC(tStdCount);
647 	tStdBaseInFile = (size_t)usGetWord(4, aucBuffer);
648 	usFtcStandardChpStsh = usGetWord(14, aucBuffer);
649 	NO_DBG_DEC(usFtcStandardChpStsh);
650 
651 	atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
652 	atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
653 	abFilled = xcalloc(tStdCount, sizeof(BOOL));
654 
655 	do {
656 		iCounter = 0;
657 		/* Read the styles one-by-one */
658 		for (iIndex = 0, tOffset = 2 + (size_t)usGetWord(0, aucBuffer);
659 		     iIndex < (int)tStdCount;
660 		     iIndex++, tOffset += 2 + tStdLen) {
661 			NO_DBG_DEC(tOffset);
662 			tStdLen = (size_t)usGetWord(tOffset, aucBuffer);
663 			NO_DBG_DEC(tStdLen);
664 			if (abFilled[iIndex]) {
665 				/* This record has already been filled */
666 				continue;
667 			}
668 			pStyle = &atStyleInfo[iIndex];
669 			pFont = &atFontInfo[iIndex];
670 			if (tStdLen == 0) {
671 				/* Empty record */
672 				vGetDefaultStyle(pStyle);
673 				vGetDefaultFont(pFont, usFtcStandardChpStsh);
674 				abFilled[iIndex] = TRUE;
675 				continue;
676 			}
677 			usTmp = usGetWord(tOffset + 4, aucBuffer);
678 			usStyleType = usTmp % 16;
679 			usBaseStyle = usTmp / 16;
680 			NO_DBG_DEC(usStyleType);
681 			NO_DBG_DEC(usBaseStyle);
682 			if (usBaseStyle == STI_NIL || usBaseStyle == STI_USER) {
683 				/* Based on the Nil style */
684 				vGetDefaultStyle(pStyle);
685 				vGetDefaultFont(pFont, usFtcStandardChpStsh);
686 			} else {
687 				iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
688 				NO_DBG_DEC(iBaseStyleIndex);
689 				if (iBaseStyleIndex < 0) {
690 					/* This base style is not known yet */
691 					continue;
692 				}
693 				fail(iBaseStyleIndex >= (int)tStdCount);
694 				fail(!abFilled[iBaseStyleIndex]);
695 				/* Based on the specified base style */
696 				*pStyle = atStyleInfo[iBaseStyleIndex];
697 				pStyle->usIstd = ISTD_INVALID;
698 				*pFont = atFontInfo[iBaseStyleIndex];
699 			}
700 			abFilled[iIndex] = TRUE;
701 			iCounter++;
702 			/* STD */
703 			usTmp = usGetWord(tOffset + 6, aucBuffer);
704 			usUpxCount = usTmp % 16;
705 			pStyle->usIstdNext = usTmp / 16;
706 			NO_DBG_DEC(usUpxCount);
707 			tPos = 2 + tStdBaseInFile;
708 			NO_DBG_DEC(tPos);
709 			tNameLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
710 			NO_DBG_DEC(tNameLen);
711 			tNameLen *= 2;	/* From Unicode characters to bytes */
712 			NO_DBG_UNICODE_N(aucBuffer + tOffset + tPos + 2,
713 					tNameLen);
714 			tNameLen += 2;	/* Include the Unicode NULL character */
715 			tPos += 2 + tNameLen;
716 			if (odd(tPos)) {
717 				tPos++;
718 			}
719 			NO_DBG_DEC(tPos);
720 			if (tPos >= tStdLen) {
721 				continue;
722 			}
723 			tUpxLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
724 			NO_DBG_DEC(tUpxLen);
725 			if (tPos + tUpxLen > tStdLen) {
726 				/* UPX length too large to be a record */
727 				DBG_DEC_C(tPos + tUpxLen > tStdLen,
728 						tPos + tUpxLen);
729 				continue;
730 			}
731 			if (usStyleType == SGC_PAP && usUpxCount >= 1) {
732 				if (tUpxLen >= 2) {
733 					NO_DBG_PRINT_BLOCK(
734 						aucBuffer + tOffset + tPos + 2,
735 						tUpxLen);
736 					pStyle->usIstd = usGetWord(
737 						tOffset + tPos + 2, aucBuffer);
738 					NO_DBG_DEC(pStyle->usIstd);
739 					NO_DBG_DEC(pStyle->usIstdNext);
740 					vGet8StyleInfo(0,
741 						aucBuffer + tOffset + tPos + 4,
742 						tUpxLen - 2, pStyle);
743 					NO_DBG_DEC(pStyle->sLeftIndent);
744 					NO_DBG_DEC(pStyle->sRightIndent);
745 					NO_DBG_HEX(pStyle->ucAlignment);
746 				}
747 				tPos += 2 + tUpxLen;
748 				if (odd(tPos)) {
749 					tPos++;
750 				}
751 				NO_DBG_DEC(tPos);
752 				tUpxLen = (size_t)usGetWord(
753 						tOffset + tPos, aucBuffer);
754 				NO_DBG_DEC(tUpxLen);
755 			}
756 			if (tUpxLen == 0 || tPos + tUpxLen > tStdLen) {
757 				/* Too small or too large to be a record */
758 				DBG_DEC_C(tPos + tUpxLen > tStdLen,
759 							tPos + tUpxLen);
760 				continue;
761 			}
762 			if ((usStyleType == SGC_PAP && usUpxCount >= 2) ||
763 			    (usStyleType == SGC_CHP && usUpxCount >= 1)) {
764 				NO_DBG_PRINT_BLOCK(
765 						aucBuffer + tOffset + tPos + 2,
766 						tUpxLen);
767 				vGet8FontInfo(0, ISTD_INVALID,
768 						aucBuffer + tOffset + tPos + 2,
769 						(int)tUpxLen, pFont);
770 				NO_DBG_DEC(pFont->usFontSize);
771 				NO_DBG_DEC(pFont->ucFontcolor);
772 				NO_DBG_HEX(pFont->usFontStyle);
773 			}
774 		}
775 		NO_DBG_DEC(iCounter);
776 	} while (iCounter > 0);
777 
778 	/* Fill records that are still empty */
779 	for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
780 		if (!abFilled[iIndex]) {
781 			NO_DBG_DEC(iIndex);
782 			vGetDefaultStyle(&atStyleInfo[iIndex]);
783 			vGetDefaultFont(&atFontInfo[iIndex],
784 					usFtcStandardChpStsh);
785 		}
786 	}
787 
788 	/* Clean up before you leave */
789 	abFilled = xfree(abFilled);
790 	aucBuffer = xfree(aucBuffer);
791 } /* end of vGet8Stylesheet */
792 
793 /*
794  * vFillStyleFromStylesheet - fill a style struct with stylesheet info
795  */
796 void
vFillStyleFromStylesheet(USHORT usIstd,style_block_type * pStyle)797 vFillStyleFromStylesheet(USHORT usIstd, style_block_type *pStyle)
798 {
799 	int	iIndex;
800 
801 	fail(pStyle == NULL);
802 
803 	if (usIstd != ISTD_INVALID && usIstd != STI_NIL && usIstd != STI_USER) {
804 		for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
805 			if (atStyleInfo[iIndex].usIstd == usIstd) {
806 				/* Right index found; return style */
807 				*pStyle = atStyleInfo[iIndex];
808 				return;
809 			}
810 		}
811 	}
812 
813 	vGetDefaultStyle(pStyle);
814 	pStyle->usIstd = usIstd;
815 } /* end of vFillStyleFromStylesheet */
816 
817 /*
818  * vFillFontFromStylesheet - fill a font struct with stylesheet info
819  */
820 void
vFillFontFromStylesheet(USHORT usIstd,font_block_type * pFont)821 vFillFontFromStylesheet(USHORT usIstd, font_block_type *pFont)
822 {
823 	int	iIndex;
824 
825 	fail(pFont == NULL);
826 
827 	if (usIstd != ISTD_INVALID && usIstd != STI_NIL && usIstd != STI_USER) {
828 		for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
829 			if (atStyleInfo[iIndex].usIstd == usIstd) {
830 				/* Right index found; return font */
831 				*pFont = atFontInfo[iIndex];
832 				return;
833 			}
834 		}
835 	}
836 
837 	vGetDefaultFont(pFont, 0);
838 } /* end of vFillFontFromStylesheet */
839