Imported from antiword-0.37.tar.gz.
[antiword.git] / fonts.c
blob77fde74ed4db93028a6c8568abf089a1f9f5adf0
1 /*
2 * fonts.c
3 * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
5 * Description:
6 * Functions to deal with fonts (generic)
7 */
9 #include <ctype.h>
10 #include <string.h>
11 #include "antiword.h"
13 /* Maximum line length in the font file */
14 #define FONT_LINE_LENGTH 81
16 /* Pitch */
17 #define PITCH_UNKNOWN 0
18 #define PITCH_FIXED 1
19 #define PITCH_VARIABLE 2
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
29 /* Font Translation Table */
30 static size_t tFontTableRecords = 0;
31 static font_table_type *pFontTable = NULL;
34 * Find the given font in the font table
36 * returns the index into the FontTable, -1 if not found
38 int
39 iGetFontByNumber(UCHAR ucWordFontNumber, USHORT usFontStyle)
41 int iIndex;
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;
50 DBG_DEC(ucWordFontNumber);
51 DBG_HEX(usFontStyle);
52 return -1;
53 } /* end of iGetFontByNumber */
56 * szGetOurFontname - Get our font name
58 * return our font name from the given index, NULL if not found
60 const char *
61 szGetOurFontname(int iIndex)
63 if (iIndex < 0 || iIndex >= (int)tFontTableRecords) {
64 return NULL;
66 return pFontTable[iIndex].szOurFontname;
67 } /* end of szGetOurFontname */
70 * Find the given font in the font table
72 * returns the Word font number, -1 if not found
74 int
75 iFontname2Fontnumber(const char *szOurFontname, USHORT usFontStyle)
77 int iIndex;
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;
85 return -1;
86 } /* end of iFontname2Fontnumber */
89 * szGetDefaultFont - get the default font that matches the parameters
91 static const char *
92 szGetDefaultFont(UCHAR ucFFN, int iEmphasis)
94 UCHAR ucPrq, ucFf;
96 fail(iEmphasis < 0 || iEmphasis > 3);
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;
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;
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;
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;
135 } /* end of szGetDefaultFont */
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).
143 static BOOL
144 bFontEqual(const UCHAR *aucWord, const char *szTable, int iBytesPerChar)
146 const UCHAR *pucTmp;
147 const char *pcTmp;
149 fail(aucWord == NULL || szTable == NULL);
150 fail(iBytesPerChar != 1 && iBytesPerChar != 2);
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;
160 return *pcTmp == '\0';
161 } /* end of bFontEqual */
164 * vFontname2Table - add fontnames to the font table
166 static void
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)
172 BOOL bMatchFound;
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);
182 bMatchFound = bFontEqual(aucFont, szWordFont, iBytesPerChar);
184 if (!bMatchFound && aucAltFont != NULL) {
185 bMatchFound = bFontEqual(aucAltFont, szWordFont, iBytesPerChar);
188 if (!bMatchFound &&
189 pFontTableRecord->szWordFontname[0] == '\0' &&
190 szWordFont[0] == '*' &&
191 szWordFont[1] == '\0') {
193 * szWordFont contains a "*", so szOurFont will contain the
194 * "default default" font. See if we can do better than that.
196 szOurFont = szGetDefaultFont(ucFFN, iEmphasis);
197 bMatchFound = TRUE;
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;
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;
228 } /* end of vFontname2Table */
231 * vCreateFontTable - Create and initialize the internal font table
233 static void
234 vCreateFontTable(void)
236 font_table_type *pTmp;
237 int iNbr;
239 if (tFontTableRecords == 0) {
240 pFontTable = xfree(pFontTable);
241 return;
244 /* Create the font table */
245 pFontTable = xcalloc(tFontTableRecords, sizeof(*pFontTable));
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;
270 } /* end of vCreateFontTable */
273 * vMinimizeFontTable - make the font table as small as possible
275 static void
276 vMinimizeFontTable(void)
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;
285 NO_DBG_MSG("vMinimizeFontTable");
287 if (tFontTableRecords == 0) {
288 pFontTable = xfree(pFontTable);
289 return;
292 /* See if we must add a font for our tables */
293 bMustAddTableFont = TRUE;
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);
306 #endif /* DEBUG */
308 /* See which fonts/styles we really need */
310 /* Default font/style is by definition in use */
311 pFontTable[0].ucInUse = 1;
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++;
320 if (bIsItalic(pFont->usFontStyle)) {
321 pTmp += 2;
323 if (pTmp >= pFontTable + tFontTableRecords) {
324 continue;
326 if (STREQ(pTmp->szOurFontname, TABLE_FONT)) {
327 /* The table font is already present */
328 bMustAddTableFont = FALSE;
330 pTmp->ucInUse = 1;
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++;
342 if (bIsItalic(tFontNext.usFontStyle)) {
343 pTmp += 2;
345 if (pTmp >= pFontTable + tFontTableRecords) {
346 continue;
348 if (STREQ(pTmp->szOurFontname, TABLE_FONT)) {
349 /* The table font is already present */
350 bMustAddTableFont = FALSE;
352 pTmp->ucInUse = 1;
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;
364 if (iUnUsed > 0) {
365 fail(pTmp - iUnUsed <= pFontTable);
366 *(pTmp - iUnUsed) = *pTmp;
369 fail(iUnUsed < 0);
370 fail(tFontTableRecords <= (size_t)iUnUsed);
371 tFontTableRecords -= (size_t)iUnUsed;
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--;
384 if (iUnUsed > 0) {
385 /* Resize the font table */
386 pFontTable = xrealloc(pFontTable,
387 tFontTableRecords * sizeof(*pFontTable));
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);
400 #endif /* DEBUG */
401 } /* end of vMinimizeFontTable */
404 * bReadFontFile - read and check a line from the font translation file
406 * returns TRUE when a correct line has been read, otherwise FALSE
408 static BOOL
409 bReadFontFile(FILE *pFontTableFile, char *szWordFont,
410 int *piItalic, int *piBold, char *szOurFont, int *piSpecial)
412 char *pcTmp;
413 int iFields;
414 char szLine[FONT_LINE_LENGTH];
416 fail(szWordFont == NULL || szOurFont == NULL);
417 fail(piItalic == NULL || piBold == NULL || piSpecial == NULL);
419 while (fgets(szLine, (int)sizeof(szLine), pFontTableFile) != NULL) {
420 if (szLine[0] == '#' ||
421 szLine[0] == '\n' ||
422 szLine[0] == '\r') {
423 continue;
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';
433 pcTmp = strchr(szLine, '\n');
434 if (pcTmp != NULL) {
435 *pcTmp = '\0';
437 DBG_DEC(iFields);
438 werr(0, "Syntax error in: '%s'", szLine);
439 continue;
441 if (strlen(szWordFont) >=
442 sizeof(pFontTable[0].szWordFontname)) {
443 werr(0, "Word fontname too long: '%s'", szWordFont);
444 continue;
446 if (strlen(szOurFont) >=
447 sizeof(pFontTable[0].szOurFontname)) {
448 werr(0, "Local fontname too long: '%s'", szOurFont);
449 continue;
451 /* The current line passed all the tests */
452 return TRUE;
454 return FALSE;
455 } /* end of bReadFontFile */
458 * vCreate0FontTable - create a font table from Word for DOS
460 void
461 vCreate0FontTable(void)
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];
470 tFontTableRecords = 0;
471 pFontTable = xfree(pFontTable);
473 pFontTableFile = pOpenFontTableFile();
474 if (pFontTableFile == NULL) {
475 /* No translation table file, no translation table */
476 return;
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();
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++;
495 if (iItalic != 0) {
496 iEmphasis += 2;
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";
510 ucFFN = (ucFf << 4) | ucPrq;
511 vFontname2Table(aucFont, NULL, 1, iEmphasis,
512 ucFFN, szWordFont, szOurFont, pTmp);
515 (void)fclose(pFontTableFile);
516 vMinimizeFontTable();
517 } /* end of vCreate0FontTable */
520 * vCreate2FontTable - create a font table from WinWord 1/2
522 void
523 vCreate2FontTable(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
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];
536 fail(pFile == NULL || aucHeader == NULL);
537 fail(iWordVersion != 1 && iWordVersion != 2);
539 tFontTableRecords = 0;
540 pFontTable = xfree(pFontTable);
542 pFontTableFile = pOpenFontTableFile();
543 if (pFontTableFile == NULL) {
544 /* No translation table file, no translation table */
545 return;
548 ulBeginFontInfo = ulGetLong(0xb2, aucHeader); /* fcSttbfffn */
549 DBG_HEX(ulBeginFontInfo);
550 tFontInfoLen = (size_t)usGetWord(0xb6, aucHeader); /* cbSttbfffn */
551 DBG_DEC(tFontInfoLen);
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;
560 aucBuffer = xmalloc(tFontInfoLen);
561 if (!bReadBytes(aucBuffer, tFontInfoLen, ulBeginFontInfo, pFile)) {
562 aucBuffer = xfree(aucBuffer);
563 (void)fclose(pFontTableFile);
564 return;
566 NO_DBG_PRINT_BLOCK(aucBuffer, tFontInfoLen);
567 DBG_DEC(usGetWord(0, aucBuffer));
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;
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++;
589 tFontTableRecords *= 4; /* Plain, Bold, Italic and Bold/Italic */
590 tFontTableRecords++; /* One extra for the table-font */
591 vCreateFontTable();
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);
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++;
644 if (iItalic != 0) {
645 iEmphasis += 2;
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;
659 (void)fclose(pFontTableFile);
660 aucBuffer = xfree(aucBuffer);
661 vMinimizeFontTable();
662 } /* end of vCreate2FontTable */
665 * vCreate6FontTable - create a font table from Word 6/7
667 void
668 vCreate6FontTable(FILE *pFile, ULONG ulStartBlock,
669 const ULONG *aulBBD, size_t tBBDLen,
670 const UCHAR *aucHeader)
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];
683 fail(pFile == NULL || aucHeader == NULL);
684 fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
685 fail(aulBBD == NULL);
687 tFontTableRecords = 0;
688 pFontTable = xfree(pFontTable);
690 pFontTableFile = pOpenFontTableFile();
691 if (pFontTableFile == NULL) {
692 /* No translation table file, no translation table */
693 return;
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);
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;
710 DBG_DEC(usGetWord(0, aucBuffer));
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++;
725 tFontTableRecords *= 4; /* Plain, Bold, Italic and Bold/italic */
726 tFontTableRecords++; /* One extra for the table-font */
727 vCreateFontTable();
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++;
739 if (iItalic != 0) {
740 iEmphasis += 2;
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);
756 vFontname2Table(aucFont, aucAltFont, 1, iEmphasis,
757 ucFFN, szWordFont, szOurFont, pTmp);
758 pTmp += 4;
759 iPos += iRecLen + 1;
762 (void)fclose(pFontTableFile);
763 aucBuffer = xfree(aucBuffer);
764 vMinimizeFontTable();
765 } /* end of vCreate6FontTable */
768 * vCreate8FontTable - create a font table from Word 8/9/10
770 void
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)
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];
788 fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
789 fail(aulBBD == NULL || aulSBD == NULL);
791 tFontTableRecords = 0;
792 pFontTable = xfree(pFontTable);
794 pFontTableFile = pOpenFontTableFile();
795 if (pFontTableFile == NULL) {
796 /* No translation table file, no translation table */
797 return;
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);
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;
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;
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;
833 NO_DBG_PRINT_BLOCK(aucBuffer, tFontInfoLen);
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();
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++;
851 if (iItalic != 0) {
852 iEmphasis += 2;
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);
868 vFontname2Table(aucFont, aucAltFont, 2, iEmphasis,
869 ucFFN, szWordFont, szOurFont, pTmp);
870 pTmp += 4;
871 iPos += iRecLen + 1;
874 (void)fclose(pFontTableFile);
875 aucBuffer = xfree(aucBuffer);
876 vMinimizeFontTable();
877 } /* end of vCreate8FontTable */
880 * Destroy the internal font table by freeing its memory
882 void
883 vDestroyFontTable(void)
885 DBG_MSG("vDestroyFontTable");
887 tFontTableRecords = 0;
888 pFontTable = xfree(pFontTable);
889 } /* end of vDestroyFontTable */
892 * pGetNextFontTableRecord
894 * returns the next record in the table or NULL if there is no next record
896 const font_table_type *
897 pGetNextFontTableRecord(const font_table_type *pRecordCurr)
899 size_t tIndexCurr;
901 if (pRecordCurr == NULL) {
902 /* No current record, so start with the first one */
903 return &pFontTable[0];
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;
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];
919 /* There is no next record */
920 return NULL;
921 } /* end of pGetNextFontTableRecord */
924 * tGetFontTableLength
926 * returns the number of records in the internal font table
928 size_t
929 tGetFontTableLength(void)
931 return tFontTableRecords;
932 } /* end of tGetFontTableLength */
934 #if !defined(__riscos)
936 * vCorrect4PDF - only include PDF default fonts
938 static void
939 vCorrect4PDF(void)
941 font_table_type *pTmp;
942 const char *szOurFont;
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;
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';
966 } /* end of vCorrect4PDF */
969 * vCorrect4CyrPS - only include monospaced fonts
971 static void
972 vCorrect4CyrPS(void)
974 font_table_type *pTmp;
975 const char *szOurFont;
976 UCHAR ucFFN;
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';
985 } /* end of vCorrect4CyrPS */
986 #endif /* __riscos */
989 * vCorrectFontTable - correct the font table in special cases
991 void
992 vCorrectFontTable(conversion_type eConversionType, encoding_type eEncoding)
994 #if !defined(__riscos)
995 if (eConversionType == conversion_pdf) {
996 vCorrect4PDF();
998 if (eConversionType == conversion_ps &&
999 eEncoding == encoding_cyrillic) {
1000 vCorrect4CyrPS();
1002 #endif /* __riscos */
1003 } /* end of vCorrectFontTable */
1006 * lComputeSpaceWidth - compute the width of a space character
1008 * Returns the space width in millipoints
1010 long
1011 lComputeSpaceWidth(drawfile_fontref tFontRef, USHORT usFontSize)
1013 char szSpace[] = " ";
1015 fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1017 return lComputeStringWidth(szSpace, 1, tFontRef, usFontSize);
1018 } /* end of lComputeSpaceWidth */