xref: /plan9/sys/src/cmd/aux/antiword/fonts.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * fonts.c
3  * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
4  *
5  * Description:
6  * Functions to deal with fonts (generic)
7  */
8 
9 #include <ctype.h>
10 #include <string.h>
11 #include "antiword.h"
12 
13 /* Maximum line length in the font file */
14 #define FONT_LINE_LENGTH	81
15 
16 /* Pitch */
17 #define PITCH_UNKNOWN		0
18 #define PITCH_FIXED		1
19 #define PITCH_VARIABLE		2
20 
21 /* Font Family */
22 #define FAMILY_UNKNOWN		0
23 #define FAMILY_ROMAN		1
24 #define FAMILY_SWISS		2
25 #define FAMILY_MODERN		3
26 #define FAMILY_SCRIPT		4
27 #define FAMILY_DECORATIVE	5
28 
29 /* Font Translation Table */
30 static size_t		tFontTableRecords = 0;
31 static font_table_type	*pFontTable = NULL;
32 
33 /*
34  * Find the given font in the font table
35  *
36  * returns the index into the FontTable, -1 if not found
37  */
38 int
iGetFontByNumber(UCHAR ucWordFontNumber,USHORT usFontStyle)39 iGetFontByNumber(UCHAR ucWordFontNumber, USHORT usFontStyle)
40 {
41 	int	iIndex;
42 
43 	for (iIndex = 0; iIndex < (int)tFontTableRecords; iIndex++) {
44 		if (ucWordFontNumber == pFontTable[iIndex].ucWordFontNumber &&
45 		    usFontStyle == pFontTable[iIndex].usFontStyle &&
46 		    pFontTable[iIndex].szOurFontname[0] != '\0') {
47 			return iIndex;
48 		}
49 	}
50 	DBG_DEC(ucWordFontNumber);
51 	DBG_HEX(usFontStyle);
52 	return -1;
53 } /* end of iGetFontByNumber */
54 
55 /*
56  * szGetOurFontname - Get our font name
57  *
58  * return our font name from the given index, NULL if not found
59  */
60 const char *
szGetOurFontname(int iIndex)61 szGetOurFontname(int iIndex)
62 {
63 	if (iIndex < 0 || iIndex >= (int)tFontTableRecords) {
64 		return NULL;
65 	}
66 	return pFontTable[iIndex].szOurFontname;
67 } /* end of szGetOurFontname */
68 
69 /*
70  * Find the given font in the font table
71  *
72  * returns the Word font number, -1 if not found
73  */
74 int
iFontname2Fontnumber(const char * szOurFontname,USHORT usFontStyle)75 iFontname2Fontnumber(const char *szOurFontname, USHORT usFontStyle)
76 {
77 	int	iIndex;
78 
79 	for (iIndex = 0; iIndex < (int)tFontTableRecords; iIndex++) {
80 		if (pFontTable[iIndex].usFontStyle == usFontStyle &&
81 		    STREQ(pFontTable[iIndex].szOurFontname, szOurFontname)) {
82 			return (int)pFontTable[iIndex].ucWordFontNumber;
83 		}
84 	}
85 	return -1;
86 } /* end of iFontname2Fontnumber */
87 
88 /*
89  * szGetDefaultFont - get the default font that matches the parameters
90  */
91 static const char *
szGetDefaultFont(UCHAR ucFFN,int iEmphasis)92 szGetDefaultFont(UCHAR ucFFN, int iEmphasis)
93 {
94 	UCHAR	ucPrq, ucFf;
95 
96 	fail(iEmphasis < 0 || iEmphasis > 3);
97 
98 	ucPrq = ucFFN & 0x03;
99 	ucFf = (ucFFN & 0x70) >> 4;
100 	NO_DBG_DEC(ucPrq);
101 	NO_DBG_DEC(ucFf);
102 	if (ucPrq == PITCH_FIXED) {
103 		/* Set to the default monospaced font */
104 		switch (iEmphasis) {
105 		case 1: return FONT_MONOSPACED_BOLD;
106 		case 2: return FONT_MONOSPACED_ITALIC;
107 		case 3: return FONT_MONOSPACED_BOLDITALIC;
108 		default: return FONT_MONOSPACED_PLAIN;
109 		}
110 	} else if (ucFf == FAMILY_ROMAN) {
111 		/* Set to the default serif font */
112 		switch (iEmphasis) {
113 		case 1: return FONT_SERIF_BOLD;
114 		case 2: return FONT_SERIF_ITALIC;
115 		case 3: return FONT_SERIF_BOLDITALIC;
116 		default: return FONT_SERIF_PLAIN;
117 		}
118 	} else if (ucFf == FAMILY_SWISS) {
119 		/* Set to the default sans serif font */
120 		switch (iEmphasis) {
121 		case 1: return FONT_SANS_SERIF_BOLD;
122 		case 2: return FONT_SANS_SERIF_ITALIC;
123 		case 3: return FONT_SANS_SERIF_BOLDITALIC;
124 		default: return FONT_SANS_SERIF_PLAIN;
125 		}
126 	} else {
127 		/* Set to the default default font */
128 		switch (iEmphasis) {
129 		case 1: return FONT_SERIF_BOLD;
130 		case 2: return FONT_SERIF_ITALIC;
131 		case 3: return FONT_SERIF_BOLDITALIC;
132 		default: return FONT_SERIF_PLAIN;
133 		}
134 	}
135 } /* end of szGetDefaultFont */
136 
137 /*
138  * See if the fontname from the Word file matches the fontname from the
139  * font translation file.
140  * If iBytesPerChar is one than aucWord is in ISO-8859-x (Word 2/6/7),
141  * if iBytesPerChar is two than aucWord is in Unicode (Word 8/9/10).
142  */
143 static BOOL
bFontEqual(const UCHAR * aucWord,const char * szTable,int iBytesPerChar)144 bFontEqual(const UCHAR *aucWord, const char *szTable, int iBytesPerChar)
145 {
146 	const UCHAR	*pucTmp;
147 	const char	*pcTmp;
148 
149 	fail(aucWord == NULL || szTable == NULL);
150 	fail(iBytesPerChar != 1 && iBytesPerChar != 2);
151 
152 	for (pucTmp = aucWord, pcTmp = szTable;
153 	     *pucTmp != 0;
154 	     pucTmp += iBytesPerChar, pcTmp++) {
155 		if (ulToUpper((ULONG)*pucTmp) !=
156 		    ulToUpper((ULONG)(UCHAR)*pcTmp)) {
157 			return FALSE;
158 		}
159 	}
160 	return *pcTmp == '\0';
161 } /* end of bFontEqual */
162 
163 /*
164  * vFontname2Table - add fontnames to the font table
165  */
166 static void
vFontname2Table(const UCHAR * aucFont,const UCHAR * aucAltFont,int iBytesPerChar,int iEmphasis,UCHAR ucFFN,const char * szWordFont,const char * szOurFont,font_table_type * pFontTableRecord)167 vFontname2Table(const UCHAR *aucFont, const UCHAR *aucAltFont,
168 	int iBytesPerChar, int iEmphasis, UCHAR ucFFN,
169 	const char *szWordFont, const char *szOurFont,
170 	font_table_type *pFontTableRecord)
171 {
172 	BOOL	bMatchFound;
173 
174 	fail(aucFont == NULL || aucFont[0] == 0);
175 	fail(aucAltFont != NULL && aucAltFont[0] == 0);
176 	fail(iBytesPerChar != 1 && iBytesPerChar != 2);
177 	fail(iEmphasis < 0 || iEmphasis > 3);
178 	fail(szWordFont == NULL || szWordFont[0] == '\0');
179 	fail(szOurFont == NULL || szOurFont[0] == '\0');
180 	fail(pFontTableRecord == NULL);
181 
182 	bMatchFound = bFontEqual(aucFont, szWordFont, iBytesPerChar);
183 
184 	if (!bMatchFound && aucAltFont != NULL) {
185 		bMatchFound = bFontEqual(aucAltFont, szWordFont, iBytesPerChar);
186 	}
187 
188 	if (!bMatchFound &&
189 	    pFontTableRecord->szWordFontname[0] == '\0' &&
190 	    szWordFont[0] == '*' &&
191 	    szWordFont[1] == '\0') {
192 		/*
193 		 * szWordFont contains a "*", so szOurFont will contain the
194 		 * "default default" font. See if we can do better than that.
195 		 */
196 		szOurFont = szGetDefaultFont(ucFFN, iEmphasis);
197 		bMatchFound = TRUE;
198 	}
199 
200 	if (bMatchFound) {
201 		switch (iBytesPerChar) {
202 		case 1:
203 			(void)strncpy(pFontTableRecord->szWordFontname,
204 				(const char *)aucFont,
205 				sizeof(pFontTableRecord->szWordFontname) - 1);
206 			break;
207 		case 2:
208 			(void)unincpy(pFontTableRecord->szWordFontname,
209 				aucFont,
210 				sizeof(pFontTableRecord->szWordFontname) - 1);
211 			break;
212 		default:
213 			DBG_FIXME();
214 			pFontTableRecord->szWordFontname[0] = '\0';
215 			break;
216 		}
217 		pFontTableRecord->szWordFontname[
218 			sizeof(pFontTableRecord->szWordFontname) - 1] = '\0';
219 		(void)strncpy(pFontTableRecord->szOurFontname, szOurFont,
220 			sizeof(pFontTableRecord->szOurFontname) - 1);
221 		pFontTableRecord->szOurFontname[
222 			sizeof(pFontTableRecord->szOurFontname) - 1] = '\0';
223 		NO_DBG_MSG(pFontTableRecord->szWordFontname);
224 		NO_DBG_MSG(pFontTableRecord->szOurFontname);
225 		pFontTableRecord->ucFFN = ucFFN;
226 		pFontTableRecord->ucEmphasis = (UCHAR)iEmphasis;
227 	}
228 } /* end of vFontname2Table */
229 
230 /*
231  * vCreateFontTable - Create and initialize the internal font table
232  */
233 static void
vCreateFontTable(void)234 vCreateFontTable(void)
235 {
236 	font_table_type	*pTmp;
237 	int	iNbr;
238 
239 	if (tFontTableRecords == 0) {
240 		pFontTable = xfree(pFontTable);
241 		return;
242 	}
243 
244 	/* Create the font table */
245 	pFontTable = xcalloc(tFontTableRecords, sizeof(*pFontTable));
246 
247 	/* Initialize the font table */
248 	for (iNbr = 0, pTmp = pFontTable;
249 	     pTmp < pFontTable + tFontTableRecords;
250 	     iNbr++, pTmp++) {
251 		pTmp->ucWordFontNumber = (UCHAR)(iNbr / 4);
252 		switch (iNbr % 4) {
253 		case 0:
254 			pTmp->usFontStyle = FONT_REGULAR;
255 			break;
256 		case 1:
257 			pTmp->usFontStyle = FONT_BOLD;
258 			break;
259 		case 2:
260 			pTmp->usFontStyle = FONT_ITALIC;
261 			break;
262 		case 3:
263 			pTmp->usFontStyle = FONT_BOLD|FONT_ITALIC;
264 			break;
265 		default:
266 			DBG_DEC(iNbr);
267 			break;
268 		}
269 	}
270 } /* end of vCreateFontTable */
271 
272 /*
273  * vMinimizeFontTable - make the font table as small as possible
274  */
275 static void
vMinimizeFontTable(void)276 vMinimizeFontTable(void)
277 {
278 	font_block_type		tFontNext;
279 	const style_block_type	*pStyle;
280 	const font_block_type	*pFont;
281 	font_table_type		*pTmp;
282 	int	iUnUsed;
283 	BOOL	bMustAddTableFont;
284 
285 	NO_DBG_MSG("vMinimizeFontTable");
286 
287 	if (tFontTableRecords == 0) {
288 		pFontTable = xfree(pFontTable);
289 		return;
290 	}
291 
292 	/* See if we must add a font for our tables */
293 	bMustAddTableFont = TRUE;
294 
295 #if 0
296 	DBG_MSG("Before");
297 	DBG_DEC(tFontTableRecords);
298 	for (pTmp = pFontTable;
299 	     pTmp < pFontTable + tFontTableRecords;
300 	     pTmp++) {
301 		DBG_DEC(pTmp->ucWordFontNumber);
302 		DBG_HEX(pTmp->usFontStyle);
303 		DBG_MSG(pTmp->szWordFontname);
304 		DBG_MSG(pTmp->szOurFontname);
305 	}
306 #endif /* DEBUG */
307 
308 	/* See which fonts/styles we really need */
309 
310 	/* Default font/style is by definition in use */
311 	pFontTable[0].ucInUse = 1;
312 
313 	/* Make InUse 1 for all the fonts/styles that WILL be used */
314 	pFont = NULL;
315 	while((pFont = pGetNextFontInfoListItem(pFont)) != NULL) {
316 		pTmp = pFontTable + 4 * (int)pFont->ucFontNumber;
317 		if (bIsBold(pFont->usFontStyle)) {
318 			pTmp++;
319 		}
320 		if (bIsItalic(pFont->usFontStyle)) {
321 			pTmp += 2;
322 		}
323 		if (pTmp >= pFontTable + tFontTableRecords) {
324 			continue;
325 		}
326 		if (STREQ(pTmp->szOurFontname, TABLE_FONT)) {
327 			/* The table font is already present */
328 			bMustAddTableFont = FALSE;
329 		}
330 		pTmp->ucInUse = 1;
331 	}
332 
333 	/* Make InUse 1 for all the fonts/styles that MIGHT be used */
334 	pStyle = NULL;
335 	while((pStyle = pGetNextStyleInfoListItem(pStyle)) != NULL) {
336 		vFillFontFromStylesheet(pStyle->usIstdNext, &tFontNext);
337 		vCorrectFontValues(&tFontNext);
338 		pTmp = pFontTable + 4 * (int)tFontNext.ucFontNumber;
339 		if (bIsBold(tFontNext.usFontStyle)) {
340 			pTmp++;
341 		}
342 		if (bIsItalic(tFontNext.usFontStyle)) {
343 			pTmp += 2;
344 		}
345 		if (pTmp >= pFontTable + tFontTableRecords) {
346 			continue;
347 		}
348 		if (STREQ(pTmp->szOurFontname, TABLE_FONT)) {
349 			/* The table font is already present */
350 			bMustAddTableFont = FALSE;
351 		}
352 		pTmp->ucInUse = 1;
353 	}
354 
355 	/* Remove the unused font entries from the font table */
356 	iUnUsed = 0;
357 	for (pTmp = pFontTable;
358 	     pTmp < pFontTable + tFontTableRecords;
359 	     pTmp++) {
360 		if (pTmp->ucInUse == 0) {
361 			iUnUsed++;
362 			continue;
363 		}
364 		if (iUnUsed > 0) {
365 			fail(pTmp - iUnUsed <= pFontTable);
366 			*(pTmp - iUnUsed) = *pTmp;
367 		}
368 	}
369 	fail(iUnUsed < 0);
370 	fail(tFontTableRecords <= (size_t)iUnUsed);
371 	tFontTableRecords -= (size_t)iUnUsed;
372 
373 	if (bMustAddTableFont) {
374 		pTmp = pFontTable + tFontTableRecords;
375 		fail(pTmp <= pFontTable);
376 		pTmp->ucWordFontNumber = (pTmp - 1)->ucWordFontNumber + 1;
377 		pTmp->usFontStyle = FONT_REGULAR;
378 		pTmp->ucInUse = 1;
379 		strcpy(pTmp->szWordFontname, "Extra Table Font");
380 		strcpy(pTmp->szOurFontname, TABLE_FONT);
381 		tFontTableRecords++;
382 		iUnUsed--;
383 	}
384 	if (iUnUsed > 0) {
385 		/* Resize the font table */
386 		pFontTable = xrealloc(pFontTable,
387 				tFontTableRecords * sizeof(*pFontTable));
388 	}
389 #if defined(DEBUG)
390 	DBG_MSG("After");
391 	DBG_DEC(tFontTableRecords);
392 	for (pTmp = pFontTable;
393 	     pTmp < pFontTable + tFontTableRecords;
394 	     pTmp++) {
395 		DBG_DEC(pTmp->ucWordFontNumber);
396 		DBG_HEX(pTmp->usFontStyle);
397 		DBG_MSG(pTmp->szWordFontname);
398 		DBG_MSG(pTmp->szOurFontname);
399 	}
400 #endif /* DEBUG */
401 } /* end of vMinimizeFontTable */
402 
403 /*
404  * bReadFontFile - read and check a line from the font translation file
405  *
406  * returns TRUE when a correct line has been read, otherwise FALSE
407  */
408 static BOOL
bReadFontFile(FILE * pFontTableFile,char * szWordFont,int * piItalic,int * piBold,char * szOurFont,int * piSpecial)409 bReadFontFile(FILE *pFontTableFile, char *szWordFont,
410 	int *piItalic, int *piBold, char *szOurFont, int *piSpecial)
411 {
412 	char	*pcTmp;
413 	int	iFields;
414 	char	szLine[FONT_LINE_LENGTH];
415 
416 	fail(szWordFont == NULL || szOurFont == NULL);
417 	fail(piItalic == NULL || piBold == NULL || piSpecial == NULL);
418 
419 	while (fgets(szLine, (int)sizeof(szLine), pFontTableFile) != NULL) {
420 		if (szLine[0] == '#' ||
421 		    szLine[0] == '\n' ||
422 		    szLine[0] == '\r') {
423 			continue;
424 		}
425 		iFields = sscanf(szLine, "%[^,],%d,%d,%1s%[^,],%d",
426 			szWordFont, piItalic, piBold,
427 			&szOurFont[0], &szOurFont[1], piSpecial);
428 		if (iFields != 6) {
429 			pcTmp = strchr(szLine, '\r');
430 			if (pcTmp != NULL) {
431 				*pcTmp = '\0';
432 			}
433 			pcTmp = strchr(szLine, '\n');
434 			if (pcTmp != NULL) {
435 				*pcTmp = '\0';
436 			}
437 			DBG_DEC(iFields);
438 			werr(0, "Syntax error in: '%s'", szLine);
439 			continue;
440 		}
441 		if (strlen(szWordFont) >=
442 				sizeof(pFontTable[0].szWordFontname)) {
443 			werr(0, "Word fontname too long: '%s'", szWordFont);
444 			continue;
445 		}
446 		if (strlen(szOurFont) >=
447 				sizeof(pFontTable[0].szOurFontname)) {
448 			werr(0, "Local fontname too long: '%s'", szOurFont);
449 			continue;
450 		}
451 		/* The current line passed all the tests */
452 		return TRUE;
453 	}
454 	return FALSE;
455 } /* end of bReadFontFile */
456 
457 /*
458  * vCreate0FontTable - create a font table from Word for DOS
459  */
460 void
vCreate0FontTable(void)461 vCreate0FontTable(void)
462 {
463 	FILE	*pFontTableFile;
464 	font_table_type	*pTmp;
465 	UCHAR	*aucFont;
466 	int	iBold, iItalic, iSpecial, iEmphasis, iFtc;
467 	UCHAR	ucPrq, ucFf, ucFFN;
468 	char	szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
469 
470 	tFontTableRecords = 0;
471 	pFontTable = xfree(pFontTable);
472 
473 	pFontTableFile = pOpenFontTableFile();
474 	if (pFontTableFile == NULL) {
475 		/* No translation table file, no translation table */
476 		return;
477 	}
478 
479 	/* Get the maximum number of entries in the font table */
480 	tFontTableRecords = 64;
481 	tFontTableRecords *= 4;	/* Plain, Bold, Italic and Bold/italic */
482 	tFontTableRecords++;	/* One extra for the table-font */
483 	vCreateFontTable();
484 
485 	/* Read the font translation file */
486 	iItalic = 0;
487 	iBold = 0;
488 	iSpecial = 0;
489 	while (bReadFontFile(pFontTableFile, szWordFont,
490 			&iItalic, &iBold, szOurFont, &iSpecial)) {
491 		iEmphasis = 0;
492 		if (iBold != 0) {
493 			iEmphasis++;
494 		}
495 		if (iItalic != 0) {
496 			iEmphasis += 2;
497 		}
498 		for (iFtc = 0, pTmp = pFontTable + iEmphasis;
499 		     pTmp < pFontTable + tFontTableRecords;
500 		     iFtc++, pTmp += 4) {
501 			if (iFtc >= 16 && iFtc <= 55) {
502 				ucPrq = PITCH_VARIABLE;
503 				ucFf = FAMILY_ROMAN;
504 				aucFont = (UCHAR *)"Times";
505 			} else {
506 				ucPrq = PITCH_FIXED;
507 				ucFf = FAMILY_MODERN;
508 				aucFont = (UCHAR *)"Courier";
509 			}
510 			ucFFN = (ucFf << 4) | ucPrq;
511 			vFontname2Table(aucFont, NULL, 1, iEmphasis,
512 					ucFFN, szWordFont, szOurFont, pTmp);
513 		}
514 	}
515 	(void)fclose(pFontTableFile);
516 	vMinimizeFontTable();
517 } /* end of vCreate0FontTable */
518 
519 /*
520  * vCreate2FontTable - create a font table from WinWord 1/2
521  */
522 void
vCreate2FontTable(FILE * pFile,int iWordVersion,const UCHAR * aucHeader)523 vCreate2FontTable(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
524 {
525 	FILE	*pFontTableFile;
526 	font_table_type	*pTmp;
527 	UCHAR	*aucFont;
528 	UCHAR	*aucBuffer;
529 	ULONG	ulBeginFontInfo;
530 	size_t	tFontInfoLen;
531 	int	iPos, iOff, iRecLen;
532 	int	iBold, iItalic, iSpecial, iEmphasis;
533 	UCHAR	ucFFN;
534 	char	szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
535 
536 	fail(pFile == NULL || aucHeader == NULL);
537 	fail(iWordVersion != 1 && iWordVersion != 2);
538 
539 	tFontTableRecords = 0;
540 	pFontTable = xfree(pFontTable);
541 
542 	pFontTableFile = pOpenFontTableFile();
543 	if (pFontTableFile == NULL) {
544 		/* No translation table file, no translation table */
545 		return;
546 	}
547 
548 	ulBeginFontInfo = ulGetLong(0xb2, aucHeader); /* fcSttbfffn */
549 	DBG_HEX(ulBeginFontInfo);
550 	tFontInfoLen = (size_t)usGetWord(0xb6, aucHeader); /* cbSttbfffn */
551 	DBG_DEC(tFontInfoLen);
552 
553 	if (ulBeginFontInfo > (ULONG)LONG_MAX || tFontInfoLen == 0) {
554 		/* Don't ask me why this is needed */
555 		DBG_HEX_C(tFontInfoLen != 0, ulBeginFontInfo);
556 		(void)fclose(pFontTableFile);
557 		return;
558 	}
559 
560 	aucBuffer = xmalloc(tFontInfoLen);
561 	if (!bReadBytes(aucBuffer, tFontInfoLen, ulBeginFontInfo, pFile)) {
562 		aucBuffer = xfree(aucBuffer);
563 		(void)fclose(pFontTableFile);
564 		return;
565 	}
566 	NO_DBG_PRINT_BLOCK(aucBuffer, tFontInfoLen);
567 	DBG_DEC(usGetWord(0, aucBuffer));
568 
569 	/* Compute the maximum number of entries in the font table */
570 	if (iWordVersion == 1) {
571 		fail(tFontInfoLen < 2);
572 		/* WinWord 1 has three implicit fonts */
573 		tFontTableRecords = 3;
574 		iOff = 2;
575 	} else {
576 		fail(tFontInfoLen < 6);
577 		/* WinWord 2 and up have no implicit fonts */
578 		tFontTableRecords = 0;
579 		iOff = 3;
580 	}
581 	iPos = 2;
582 	while (iPos + iOff < (int)tFontInfoLen) {
583 		iRecLen = (int)ucGetByte(iPos, aucBuffer);
584 		NO_DBG_DEC(iRecLen);
585 		NO_DBG_MSG(aucBuffer + iPos + iOff);
586 		iPos += iRecLen + 1;
587 		tFontTableRecords++;
588 	}
589 	tFontTableRecords *= 4;	/* Plain, Bold, Italic and Bold/Italic */
590 	tFontTableRecords++;	/* One extra for the table-font */
591 	vCreateFontTable();
592 
593 	/* Add the tree implicit fonts (in four variations) */
594 	if (iWordVersion == 1) {
595 		fail(tFontTableRecords < 13);
596 		vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 0,
597 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
598 			"*", "Times-Roman", pFontTable + 0);
599 		vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 1,
600 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
601 			"*", "Times-Bold", pFontTable + 1);
602 		vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 2,
603 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
604 			"*", "Times-Italic", pFontTable + 2);
605 		vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 3,
606 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
607 			"*", "Times-BoldItalic", pFontTable + 3);
608 		vFontname2Table((UCHAR *)"Symbol", NULL, 1, 0,
609 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
610 			"*", "Times-Roman", pFontTable + 4);
611 		vFontname2Table((UCHAR *)"Symbol", NULL, 1, 1,
612 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
613 			"*", "Times-Bold", pFontTable + 5);
614 		vFontname2Table((UCHAR *)"Symbol", NULL, 1, 2,
615 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
616 			"*", "Times-Italic", pFontTable + 6);
617 		vFontname2Table((UCHAR *)"Symbol", NULL, 1, 3,
618 			(UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
619 			"*", "Times-BoldItalic", pFontTable + 7);
620 		vFontname2Table((UCHAR *)"Helv", NULL, 1, 0,
621 			(UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
622 			"*", "Helvetica", pFontTable + 8);
623 		vFontname2Table((UCHAR *)"Helv", NULL, 1, 1,
624 			(UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
625 			"*", "Helvetica-Bold", pFontTable + 9);
626 		vFontname2Table((UCHAR *)"Helv", NULL, 1, 2,
627 			(UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
628 			"*", "Helvetica-Oblique", pFontTable + 10);
629 		vFontname2Table((UCHAR *)"Helv", NULL, 1, 3,
630 			(UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
631 			"*", "Helvetica-BoldOblique", pFontTable + 11);
632 	}
633 
634 	/* Read the font translation file */
635 	iItalic = 0;
636 	iBold = 0;
637 	iSpecial = 0;
638 	while (bReadFontFile(pFontTableFile, szWordFont,
639 			&iItalic, &iBold, szOurFont, &iSpecial)) {
640 		iEmphasis = 0;
641 		if (iBold != 0) {
642 			iEmphasis++;
643 		}
644 		if (iItalic != 0) {
645 			iEmphasis += 2;
646 		}
647 		pTmp = pFontTable + iEmphasis;
648 		iPos = 2;
649 		while (iPos + iOff < (int)tFontInfoLen) {
650 			iRecLen = (int)ucGetByte(iPos, aucBuffer);
651 			ucFFN = ucGetByte(iPos + 1, aucBuffer);
652 			aucFont = aucBuffer + iPos + iOff;
653 			vFontname2Table(aucFont, NULL, 1, iEmphasis,
654 					ucFFN, szWordFont, szOurFont, pTmp);
655 			pTmp += 4;
656 			iPos += iRecLen + 1;
657 		}
658 	}
659 	(void)fclose(pFontTableFile);
660 	aucBuffer = xfree(aucBuffer);
661 	vMinimizeFontTable();
662 } /* end of vCreate2FontTable */
663 
664 /*
665  * vCreate6FontTable - create a font table from Word 6/7
666  */
667 void
vCreate6FontTable(FILE * pFile,ULONG ulStartBlock,const ULONG * aulBBD,size_t tBBDLen,const UCHAR * aucHeader)668 vCreate6FontTable(FILE *pFile, ULONG ulStartBlock,
669 	const ULONG *aulBBD, size_t tBBDLen,
670 	const UCHAR *aucHeader)
671 {
672 	FILE	*pFontTableFile;
673 	font_table_type	*pTmp;
674 	UCHAR	*aucFont, *aucAltFont;
675 	UCHAR	*aucBuffer;
676 	ULONG	ulBeginFontInfo;
677 	size_t	tFontInfoLen;
678 	int	iPos, iRecLen, iOffsetAltName;
679 	int	iBold, iItalic, iSpecial, iEmphasis;
680 	UCHAR	ucFFN;
681 	char	szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
682 
683 	fail(pFile == NULL || aucHeader == NULL);
684 	fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
685 	fail(aulBBD == NULL);
686 
687 	tFontTableRecords = 0;
688 	pFontTable = xfree(pFontTable);
689 
690 	pFontTableFile = pOpenFontTableFile();
691 	if (pFontTableFile == NULL) {
692 		/* No translation table file, no translation table */
693 		return;
694 	}
695 
696 	ulBeginFontInfo = ulGetLong(0xd0, aucHeader); /* fcSttbfffn */
697 	DBG_HEX(ulBeginFontInfo);
698 	tFontInfoLen = (size_t)ulGetLong(0xd4, aucHeader); /* lcbSttbfffn */
699 	DBG_DEC(tFontInfoLen);
700 	fail(tFontInfoLen < 9);
701 
702 	aucBuffer = xmalloc(tFontInfoLen);
703 	if (!bReadBuffer(pFile, ulStartBlock,
704 			aulBBD, tBBDLen, BIG_BLOCK_SIZE,
705 			aucBuffer, ulBeginFontInfo, tFontInfoLen)) {
706 		aucBuffer = xfree(aucBuffer);
707 		(void)fclose(pFontTableFile);
708 		return;
709 	}
710 	DBG_DEC(usGetWord(0, aucBuffer));
711 
712 	/* Compute the maximum number of entries in the font table */
713 	tFontTableRecords = 0;
714 	iPos = 2;
715 	while (iPos + 6 < (int)tFontInfoLen) {
716 		iRecLen = (int)ucGetByte(iPos, aucBuffer);
717 		NO_DBG_DEC(iRecLen);
718 		iOffsetAltName = (int)ucGetByte(iPos + 5, aucBuffer);
719 		NO_DBG_MSG(aucBuffer + iPos + 6);
720 		NO_DBG_MSG_C(iOffsetAltName > 0,
721 				aucBuffer + iPos + 6 + iOffsetAltName);
722 		iPos += iRecLen + 1;
723 		tFontTableRecords++;
724 	}
725 	tFontTableRecords *= 4;	/* Plain, Bold, Italic and Bold/italic */
726 	tFontTableRecords++;	/* One extra for the table-font */
727 	vCreateFontTable();
728 
729 	/* Read the font translation file */
730 	iItalic = 0;
731 	iBold = 0;
732 	iSpecial = 0;
733 	while (bReadFontFile(pFontTableFile, szWordFont,
734 			&iItalic, &iBold, szOurFont, &iSpecial)) {
735 		iEmphasis = 0;
736 		if (iBold != 0) {
737 			iEmphasis++;
738 		}
739 		if (iItalic != 0) {
740 			iEmphasis += 2;
741 		}
742 		pTmp = pFontTable + iEmphasis;
743 		iPos = 2;
744 		while (iPos + 6 < (int)tFontInfoLen) {
745 			iRecLen = (int)ucGetByte(iPos, aucBuffer);
746 			ucFFN = ucGetByte(iPos + 1, aucBuffer);
747 			aucFont = aucBuffer + iPos + 6;
748 			iOffsetAltName = (int)ucGetByte(iPos + 5, aucBuffer);
749 			if (iOffsetAltName <= 0) {
750 				aucAltFont = NULL;
751 			} else {
752 				aucAltFont = aucFont + iOffsetAltName;
753 				NO_DBG_MSG(aucFont);
754 				NO_DBG_MSG(aucAltFont);
755 			}
756 			vFontname2Table(aucFont, aucAltFont, 1, iEmphasis,
757 					ucFFN, szWordFont, szOurFont, pTmp);
758 			pTmp += 4;
759 			iPos += iRecLen + 1;
760 		}
761 	}
762 	(void)fclose(pFontTableFile);
763 	aucBuffer = xfree(aucBuffer);
764 	vMinimizeFontTable();
765 } /* end of vCreate6FontTable */
766 
767 /*
768  * vCreate8FontTable - create a font table from Word 8/9/10
769  */
770 void
vCreate8FontTable(FILE * pFile,const pps_info_type * pPPS,const ULONG * aulBBD,size_t tBBDLen,const ULONG * aulSBD,size_t tSBDLen,const UCHAR * aucHeader)771 vCreate8FontTable(FILE *pFile, const pps_info_type *pPPS,
772 	const ULONG *aulBBD, size_t tBBDLen,
773 	const ULONG *aulSBD, size_t tSBDLen,
774 	const UCHAR *aucHeader)
775 {
776 	FILE	*pFontTableFile;
777 	font_table_type	*pTmp;
778 	const ULONG	*aulBlockDepot;
779 	UCHAR	*aucFont, *aucAltFont;
780 	UCHAR	*aucBuffer;
781 	ULONG	ulBeginFontInfo;
782 	size_t	tFontInfoLen, tBlockDepotLen, tBlockSize;
783 	int	iPos, iRecLen, iOffsetAltName;
784 	int	iBold, iItalic, iSpecial, iEmphasis;
785 	UCHAR	ucFFN;
786 	char	szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
787 
788 	fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
789 	fail(aulBBD == NULL || aulSBD == NULL);
790 
791 	tFontTableRecords = 0;
792 	pFontTable = xfree(pFontTable);
793 
794 	pFontTableFile = pOpenFontTableFile();
795 	if (pFontTableFile == NULL) {
796 		/* No translation table file, no translation table */
797 		return;
798 	}
799 
800 	ulBeginFontInfo = ulGetLong(0x112, aucHeader); /* fcSttbfffn */
801 	DBG_HEX(ulBeginFontInfo);
802 	tFontInfoLen = (size_t)ulGetLong(0x116, aucHeader); /* lcbSttbfffn */
803 	DBG_DEC(tFontInfoLen);
804 	fail(tFontInfoLen < 46);
805 
806 	DBG_DEC(pPPS->tTable.ulSB);
807 	DBG_HEX(pPPS->tTable.ulSize);
808 	if (pPPS->tTable.ulSize == 0) {
809 		DBG_MSG("No fontname table");
810 		(void)fclose(pFontTableFile);
811 		return;
812 	}
813 
814 	if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
815 		/* Use the Small Block Depot */
816 		aulBlockDepot = aulSBD;
817 		tBlockDepotLen = tSBDLen;
818 		tBlockSize = SMALL_BLOCK_SIZE;
819 	} else {
820 		/* Use the Big Block Depot */
821 		aulBlockDepot = aulBBD;
822 		tBlockDepotLen = tBBDLen;
823 		tBlockSize = BIG_BLOCK_SIZE;
824 	}
825 	aucBuffer = xmalloc(tFontInfoLen);
826 	if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
827 			aulBlockDepot, tBlockDepotLen, tBlockSize,
828 			aucBuffer, ulBeginFontInfo, tFontInfoLen)) {
829 		aucBuffer = xfree(aucBuffer);
830 		(void)fclose(pFontTableFile);
831 		return;
832 	}
833 	NO_DBG_PRINT_BLOCK(aucBuffer, tFontInfoLen);
834 
835 	/* Get the maximum number of entries in the font table */
836 	tFontTableRecords = (size_t)usGetWord(0, aucBuffer);
837 	tFontTableRecords *= 4;	/* Plain, Bold, Italic and Bold/italic */
838 	tFontTableRecords++;	/* One extra for the table-font */
839 	vCreateFontTable();
840 
841 	/* Read the font translation file */
842 	iItalic = 0;
843 	iBold = 0;
844 	iSpecial = 0;
845 	while (bReadFontFile(pFontTableFile, szWordFont,
846 			&iItalic, &iBold, szOurFont, &iSpecial)) {
847 		iEmphasis = 0;
848 		if (iBold != 0) {
849 			iEmphasis++;
850 		}
851 		if (iItalic != 0) {
852 			iEmphasis += 2;
853 		}
854 		pTmp = pFontTable + iEmphasis;
855 		iPos = 4;
856 		while (iPos + 40 < (int)tFontInfoLen) {
857 			iRecLen = (int)ucGetByte(iPos, aucBuffer);
858 			ucFFN = ucGetByte(iPos + 1, aucBuffer);
859 			aucFont = aucBuffer + iPos + 40;
860 			iOffsetAltName = (int)unilen(aucFont);
861 			if (iPos + 40 + iOffsetAltName + 4 >= iRecLen) {
862 				aucAltFont = NULL;
863 			} else {
864 				aucAltFont = aucFont + iOffsetAltName + 2;
865 				NO_DBG_UNICODE(aucFont);
866 				NO_DBG_UNICODE(aucAltFont);
867 			}
868 			vFontname2Table(aucFont, aucAltFont, 2, iEmphasis,
869 					ucFFN, szWordFont, szOurFont, pTmp);
870 			pTmp += 4;
871 			iPos += iRecLen + 1;
872 		}
873 	}
874 	(void)fclose(pFontTableFile);
875 	aucBuffer = xfree(aucBuffer);
876 	vMinimizeFontTable();
877 } /* end of vCreate8FontTable */
878 
879 /*
880  * Destroy the internal font table by freeing its memory
881  */
882 void
vDestroyFontTable(void)883 vDestroyFontTable(void)
884 {
885 	DBG_MSG("vDestroyFontTable");
886 
887 	tFontTableRecords = 0;
888 	pFontTable = xfree(pFontTable);
889 } /* end of vDestroyFontTable */
890 
891 /*
892  * pGetNextFontTableRecord
893  *
894  * returns the next record in the table or NULL if there is no next record
895  */
896 const font_table_type *
pGetNextFontTableRecord(const font_table_type * pRecordCurr)897 pGetNextFontTableRecord(const font_table_type *pRecordCurr)
898 {
899 	size_t	tIndexCurr;
900 
901 	if (pRecordCurr == NULL) {
902 		/* No current record, so start with the first one */
903 		return &pFontTable[0];
904 	}
905 
906 	if (pRecordCurr < pFontTable ||
907 	    pRecordCurr >= pFontTable + tFontTableRecords) {
908 		/* Not a pointer in the array */
909 		DBG_HEX(pRecordCurr);
910 		DBG_HEX(pFontTable);
911 		return NULL;
912 	}
913 
914 	tIndexCurr = (size_t)(pRecordCurr - pFontTable);
915 	if (tIndexCurr + 1 < tFontTableRecords) {
916 		/* There is a next record, so return it */
917 		return &pFontTable[tIndexCurr + 1];
918 	}
919 	/* There is no next record */
920 	return NULL;
921 } /* end of pGetNextFontTableRecord */
922 
923 /*
924  * tGetFontTableLength
925  *
926  * returns the number of records in the internal font table
927  */
928 size_t
tGetFontTableLength(void)929 tGetFontTableLength(void)
930 {
931 	return tFontTableRecords;
932 } /* end of tGetFontTableLength */
933 
934 #if !defined(__riscos)
935 /*
936  * vCorrect4PDF - only include PDF default fonts
937  */
938 static void
vCorrect4PDF(void)939 vCorrect4PDF(void)
940 {
941 	font_table_type	*pTmp;
942 	const char	*szOurFont;
943 
944 	for (pTmp = pFontTable; pTmp < pFontTable + tFontTableRecords; pTmp++) {
945 		if (STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_PLAIN) ||
946 		    STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_BOLD) ||
947 		    STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_ITALIC) ||
948 		    STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_BOLDITALIC) ||
949 		    STRCEQ(pTmp->szOurFontname, FONT_SERIF_PLAIN) ||
950 		    STRCEQ(pTmp->szOurFontname, FONT_SERIF_BOLD) ||
951 		    STRCEQ(pTmp->szOurFontname, FONT_SERIF_ITALIC) ||
952 		    STRCEQ(pTmp->szOurFontname, FONT_SERIF_BOLDITALIC) ||
953 		    STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_PLAIN) ||
954 		    STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_BOLD) ||
955 		    STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_ITALIC) ||
956 		    STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_BOLDITALIC)) {
957 			/* Already a default font */
958 			continue;
959 		}
960 		szOurFont =
961 			szGetDefaultFont(pTmp->ucFFN, (int)pTmp->ucEmphasis);
962 		(void)strncpy(pTmp->szOurFontname, szOurFont,
963 			sizeof(pTmp->szOurFontname) - 1);
964 		pTmp->szOurFontname[sizeof(pTmp->szOurFontname) - 1] = '\0';
965 	}
966 } /* end of vCorrect4PDF */
967 
968 /*
969  * vCorrect4CyrPS - only include monospaced fonts
970  */
971 static void
vCorrect4CyrPS(void)972 vCorrect4CyrPS(void)
973 {
974 	font_table_type	*pTmp;
975 	const char	*szOurFont;
976 	UCHAR	ucFFN;
977 
978 	ucFFN = (FAMILY_UNKNOWN << 4) | PITCH_FIXED;
979 	for (pTmp = pFontTable; pTmp < pFontTable + tFontTableRecords; pTmp++) {
980 		szOurFont = szGetDefaultFont(ucFFN, (int)pTmp->ucEmphasis);
981 		(void)strncpy(pTmp->szOurFontname, szOurFont,
982 			sizeof(pTmp->szOurFontname) - 1);
983 		pTmp->szOurFontname[sizeof(pTmp->szOurFontname) - 1] = '\0';
984 	}
985 } /* end of vCorrect4CyrPS */
986 #endif /* __riscos */
987 
988 /*
989  * vCorrectFontTable - correct the font table in special cases
990  */
991 void
vCorrectFontTable(conversion_type eConversionType,encoding_type eEncoding)992 vCorrectFontTable(conversion_type eConversionType, encoding_type eEncoding)
993 {
994 #if !defined(__riscos)
995 	if (eConversionType == conversion_pdf) {
996 		vCorrect4PDF();
997 	}
998 	if (eConversionType == conversion_ps &&
999 	    eEncoding == encoding_cyrillic) {
1000 		vCorrect4CyrPS();
1001 	}
1002 #endif /* __riscos */
1003 } /* end of vCorrectFontTable */
1004 
1005 /*
1006  * lComputeSpaceWidth - compute the width of a space character
1007  *
1008  * Returns the space width in millipoints
1009  */
1010 long
lComputeSpaceWidth(drawfile_fontref tFontRef,USHORT usFontSize)1011 lComputeSpaceWidth(drawfile_fontref tFontRef, USHORT usFontSize)
1012 {
1013 	char	szSpace[] = " ";
1014 
1015 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1016 
1017         return lComputeStringWidth(szSpace, 1, tFontRef, usFontSize);
1018 } /* end of lComputeSpaceWidth */
1019