9 #define SAFE_FZ_READ(file, buf, size)\
10 byteread = fz_read((file), (char*)(buf), (size));\
11 if(byteread<0) err = fz_ioerror(file);\
12 if(byteread != (size)) err = fz_throw("ioerror");\
15 #define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
17 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
18 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
20 #define PLATFORM_UNICODE 0
21 #define PLATFORM_MACINTOSH 1
22 #define PLATFORM_ISO 2
23 #define PLATFORM_MICROSOFT 3
25 #define UNI_ENC_UNI_1 0
26 #define UNI_ENC_UNI_1_1 1
28 #define UNI_ENC_UNI_2_BMP 3
29 #define UNI_ENC_UNI_2_FULL_REPERTOIRE 4
32 #define MAC_JAPANESE 1
33 #define MAC_CHINESE_TRADITIONAL 2
35 #define MAC_CHINESE_SIMPLIFIED 25
37 #define MS_ENC_SYMBOL 0
38 #define MS_ENC_UNI_BMP 1
39 #define MS_ENC_SHIFTJIS 2
42 #define MS_ENC_WANSUNG 5
43 #define MS_ENC_JOHAB 6
44 #define MS_ENC_UNI_FULL_REPETOIRE 10
46 #define TTC_VERSION1 0x00010000
47 #define TTC_VERSION2 0x00020000
49 typedef struct pdf_fontmapMS_s pdf_fontmapMS
;
50 typedef struct pdf_fontlistMS_s pdf_fontlistMS
;
52 struct pdf_fontmapMS_s
55 char fontpath
[MAX_PATH
+1];
59 struct pdf_fontlistMS_s
61 pdf_fontmapMS
*fontmap
;
66 typedef struct _tagTT_OFFSET_TABLE
72 USHORT uEntrySelector
;
76 typedef struct _tagTT_TABLE_DIRECTORY
78 char szTag
[4]; //table name
79 ULONG uCheckSum
; //Check sum
80 ULONG uOffset
; //Offset from beginning of file
81 ULONG uLength
; //length of the table in bytes
84 typedef struct _tagTT_NAME_TABLE_HEADER
86 USHORT uFSelector
; //format selector. Always 0
87 USHORT uNRCount
; //Name Records count
88 USHORT uStorageOffset
; //Offset for strings storage, from start of the table
89 } TT_NAME_TABLE_HEADER
;
91 typedef struct _tagTT_NAME_RECORD
98 USHORT uStringOffset
; //from start of storage area
101 typedef struct _tagFONT_COLLECTION
108 static char *basenames
[13] =
113 "Courier-BoldOblique",
117 "Helvetica-BoldOblique",
125 static char *basepatterns
[13] =
128 "CourierNewPS-BoldMT",
129 "CourierNewPS-ItalicMT",
130 "CourierNewPS-BoldItalicMT",
134 "Arial-BoldItalicMT",
136 "TimesNewRomanPS-BoldMT",
137 "TimesNewRomanPS-ItalicMT",
138 "TimesNewRomanPS-BoldItalicMT",
142 static pdf_fontlistMS fontlistMS
=
150 compare(const void *elem1
, const void *elem2
)
152 pdf_fontmapMS
*val1
= (pdf_fontmapMS
*)elem1
;
153 pdf_fontmapMS
*val2
= (pdf_fontmapMS
*)elem2
;
155 if(val1
->fontface
[0] == 0)
157 if(val2
->fontface
[0] == 0)
160 return stricmp(val1
->fontface
, val2
->fontface
);
164 localbsearch (const void *key
, const void *base
, size_t num
,
165 size_t width
, int (*compare
)(const void *, const void *))
167 char *lo
= (char *)base
;
168 char *hi
= (char *)base
+ (num
- 1) * width
;
176 mid
= lo
+ (num
& 1 ? half
: (half
- 1)) * width
;
177 if (!(result
= (*compare
)(key
,mid
)))
182 num
= num
& 1 ? half
: half
-1;
190 return((*compare
)(key
,lo
) ? 0 : lo
);
198 removeredundancy(pdf_fontlistMS
*fl
)
202 int redundancy_count
= 0;
204 qsort(fl
->fontmap
,fl
->len
,sizeof(pdf_fontmapMS
),compare
);
205 for(i
= 0; i
< fl
->len
- 1; ++i
)
207 if(strcmp(fl
->fontmap
[i
].fontface
,fl
->fontmap
[i
+1].fontface
) == 0)
209 fl
->fontmap
[i
].fontface
[0] = 0;
213 qsort(fl
->fontmap
,fl
->len
,sizeof(pdf_fontmapMS
),compare
);
214 fl
->len
-= redundancy_count
;
216 for(i
= 0; i
< fl
->len
; ++i
)
217 fprintf(stdout
,"%s , %s , %d\n",fl
->fontmap
[i
].fontface
,
218 fl
->fontmap
[i
].fontpath
,fl
->fontmap
[i
].index
);
223 swapword(char* pbyte
, int nLen
)
230 return fz_throw("fonterror");
233 for(i
= 0; i
< nLen
; ++i
) {
235 pbyte
[i
*2] = pbyte
[i
*2+1];
241 /* pSouce and PDest can be same */
243 decodeunicodeBMP(char* source
, int sourcelen
,char* dest
, int destlen
)
247 memset(tmp
,0,sizeof(tmp
));
248 memcpy(tmp
,source
,sourcelen
);
249 swapword((char*)tmp
,sourcelen
);
251 converted
= WideCharToMultiByte(CP_ACP
, 0, tmp
,
252 -1, dest
, destlen
, NULL
, NULL
);
255 return fz_throw("fonterror");
261 decodeunicodeplatform(char* source
, int sourcelen
,char* dest
, int destlen
, int enctype
)
267 case UNI_ENC_UNI_2_BMP
:
268 err
= decodeunicodeBMP(source
,sourcelen
,dest
,destlen
);
270 case UNI_ENC_UNI_2_FULL_REPERTOIRE
:
271 case UNI_ENC_UNI_1_1
:
274 err
= fz_throw("fonterror : unsupported encoding");
281 decodemacintoshplatform(char* source
, int sourcelen
,char* dest
, int destlen
, int enctype
)
287 if(sourcelen
+ 1 > destlen
)
288 err
= fz_throw("fonterror : short buf lenth");
291 memcpy(source
,dest
,sourcelen
);
296 err
= fz_throw("fonterror : unsupported encoding");
303 decodemicrosoftplatform(char* source
, int sourcelen
,char* dest
, int destlen
, int enctype
)
310 err
= decodeunicodeBMP(source
,sourcelen
,dest
,destlen
);
313 err
= fz_throw("fonterror : unsupported encoding");
320 growfontlist(pdf_fontlistMS
*fl
)
323 pdf_fontmapMS
*newitems
;
328 newcap
= fl
->cap
* 2;
330 newitems
= fz_realloc(fl
->fontmap
, sizeof(pdf_fontmapMS
) * newcap
);
334 memset(newitems
+ fl
->cap
, 0,
335 sizeof(struct fz_keyval_s
) * (newcap
- fl
->cap
));
337 fl
->fontmap
= newitems
;
344 insertmapping(pdf_fontlistMS
*fl
, char *facename
, char *path
, int index
)
348 if(fl
->len
== fl
->cap
) {
349 err
= growfontlist(fl
);
353 if(fl
->len
>= fl
->cap
)
354 return fz_throw("fonterror : fontlist overflow");
356 strlcpy(fl
->fontmap
[fl
->len
].fontface
, facename
,
357 sizeof(fl
->fontmap
[0].fontface
));
358 strlcpy(fl
->fontmap
[fl
->len
].fontpath
, path
,
359 sizeof(fl
->fontmap
[0].fontpath
));
360 fl
->fontmap
[fl
->len
].index
= index
;
368 parseTTF(fz_stream
*file
, int offset
, int index
, char *path
)
373 TT_OFFSET_TABLE ttOffsetTable
;
374 TT_TABLE_DIRECTORY tblDir
;
375 TT_NAME_TABLE_HEADER ttNTHeader
;
376 TT_NAME_RECORD ttRecord
;
382 fz_seek(file
,offset
,0);
383 SAFE_FZ_READ(file
, &ttOffsetTable
, sizeof(TT_OFFSET_TABLE
));
385 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
386 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
387 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
389 //check is this is a true type font and the version is 1.0
390 if(ttOffsetTable
.uMajorVersion
!= 1 || ttOffsetTable
.uMinorVersion
!= 0)
391 return fz_throw("fonterror : invalid font version");
395 for(i
= 0; i
< ttOffsetTable
.uNumOfTables
; i
++)
397 SAFE_FZ_READ(file
,&tblDir
,sizeof(TT_TABLE_DIRECTORY
));
399 memcpy(szTemp
, tblDir
.szTag
, 4);
402 if (stricmp(szTemp
, "name") == 0)
405 tblDir
.uLength
= SWAPLONG(tblDir
.uLength
);
406 tblDir
.uOffset
= SWAPLONG(tblDir
.uOffset
);
409 else if (szTemp
[0] == 0)
417 fz_seek(file
,tblDir
.uOffset
,0);
419 SAFE_FZ_READ(file
,&ttNTHeader
,sizeof(TT_NAME_TABLE_HEADER
));
421 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
422 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
424 offset
= tblDir
.uOffset
+ sizeof(TT_NAME_TABLE_HEADER
);
426 for(i
= 0; i
< ttNTHeader
.uNRCount
&& err
== nil
; ++i
)
428 fz_seek(file
, offset
+ sizeof(TT_NAME_RECORD
)*i
, 0);
429 SAFE_FZ_READ(file
,&ttRecord
,sizeof(TT_NAME_RECORD
));
431 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
432 ttRecord
.uLanguageID
= SWAPWORD(ttRecord
.uLanguageID
);
435 if(ttRecord
.uNameID
== 6)
437 ttRecord
.uPlatformID
= SWAPWORD(ttRecord
.uPlatformID
);
438 ttRecord
.uEncodingID
= SWAPWORD(ttRecord
.uEncodingID
);
439 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
440 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
442 fz_seek(file
, tblDir
.uOffset
+ ttRecord
.uStringOffset
+ ttNTHeader
.uStorageOffset
, 0);
443 SAFE_FZ_READ(file
, szTemp
, ttRecord
.uStringLength
);
445 switch(ttRecord
.uPlatformID
)
447 case PLATFORM_UNICODE
:
448 err
= decodeunicodeplatform(szTemp
, ttRecord
.uStringLength
,
449 szTemp
, sizeof(szTemp
), ttRecord
.uEncodingID
);
451 case PLATFORM_MACINTOSH
:
452 err
= decodemacintoshplatform(szTemp
, ttRecord
.uStringLength
,
453 szTemp
, sizeof(szTemp
), ttRecord
.uEncodingID
);
456 err
= fz_throw("fonterror : unsupported platform");
458 case PLATFORM_MICROSOFT
:
459 err
= decodemicrosoftplatform(szTemp
, ttRecord
.uStringLength
,
460 szTemp
, sizeof(szTemp
), ttRecord
.uEncodingID
);
465 err
= insertmapping(&fontlistMS
, szTemp
, path
, index
);
475 parseTTFs(char *path
)
478 fz_stream
*file
= nil
;
480 err
= fz_openrfile(&file
, path
);
484 err
= parseTTF(file
,0,0,path
);
496 parseTTCs(char *path
)
500 fz_stream
*file
= nil
;
501 FONT_COLLECTION fontcollectioin
;
504 err
= fz_openrfile(&file
, path
);
508 SAFE_FZ_READ(file
, &fontcollectioin
, sizeof(FONT_COLLECTION
));
509 if(memcmp(fontcollectioin
.Tag
,"ttcf",sizeof(fontcollectioin
.Tag
)) == 0)
511 fontcollectioin
.Version
= SWAPLONG(fontcollectioin
.Version
);
512 fontcollectioin
.NumFonts
= SWAPLONG(fontcollectioin
.NumFonts
);
513 if( fontcollectioin
.Version
== TTC_VERSION1
||
514 fontcollectioin
.Version
== TTC_VERSION2
)
516 ULONG
*offsettable
= fz_malloc(sizeof(ULONG
)*fontcollectioin
.NumFonts
);
517 if(offsettable
== nil
)
523 SAFE_FZ_READ(file
, offsettable
, sizeof(ULONG
)*fontcollectioin
.NumFonts
);
524 for(i
= 0; i
< fontcollectioin
.NumFonts
; ++i
)
526 offsettable
[i
] = SWAPLONG(offsettable
[i
]);
527 parseTTF(file
,offsettable
[i
],i
,path
);
529 fz_free(offsettable
);
533 err
= fz_throw("fonterror : invalid version");
539 err
= fz_throw("fonterror: wrong format");
552 pdf_createfontlistMS()
554 char szFontDir
[MAX_PATH
*2];
555 char szSearch
[MAX_PATH
*2];
556 char szFile
[MAX_PATH
*2];
559 WIN32_FIND_DATA FileData
;
562 if (fontlistMS
.len
!= 0)
565 GetWindowsDirectory(szFontDir
, sizeof(szFontDir
));
567 // Get the proper directory path
568 strcat(szFontDir
,"\\Fonts\\");
569 sprintf(szSearch
,"%s*.tt?",szFontDir
);
570 // Get the first file
571 hList
= FindFirstFile(szSearch
, &FileData
);
572 if (hList
== INVALID_HANDLE_VALUE
)
574 /* Don't complain about missing directories */
576 return fz_throw("fonterror : can't find system fonts dir");
577 return fz_throw("ioerror");
579 // Traverse through the directory structure
583 if (!(FileData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
585 // Get the full path for sub directory
586 sprintf(szFile
,"%s%s", szFontDir
, FileData
.cFileName
);
587 if (szFile
[strlen(szFile
)-1] == 'c' || szFile
[strlen(szFile
)-1] == 'C')
589 err
= parseTTCs(szFile
);
590 // ignore error parsing a given font file
592 else if (szFile
[strlen(szFile
)-1] == 'f'|| szFile
[strlen(szFile
)-1] == 'F')
594 err
= parseTTFs(szFile
);
595 // ignore error parsing a given font file
599 if (!FindNextFile(hList
, &FileData
))
601 if (GetLastError() == ERROR_NO_MORE_FILES
)
608 removeredundancy(&fontlistMS
);
613 pdf_destoryfontlistMS()
615 if (fontlistMS
.fontmap
!= nil
)
616 fz_free(fontlistMS
.fontmap
);
622 #if 0 /* This is for testing if localbsearch() fails unexpectedly */
624 findlinear(pdf_fontlistMS
*list
, pdf_fontmapMS
*item
)
627 pdf_fontmapMS
*curritem
= list
->fontmap
;
630 for (i
= 0; i
< len
; i
++)
632 if (0 == stricmp(curritem
->fontface
, item
->fontface
))
641 pdf_lookupfontMS(char *fontname
, char **fontpath
, int *index
)
643 pdf_fontmapMS fontmap
;
644 pdf_fontmapMS
*found
= nil
;
648 if (fontlistMS
.len
== 0)
649 return fz_throw("fonterror : no fonts in the system");
652 for (i
= 0; i
< ARRAY_SIZE(basenames
); i
++)
654 if (0 == strcmp(fontname
, basenames
[i
]))
656 pattern
= basepatterns
[i
];
661 strlcpy(fontmap
.fontface
,pattern
,sizeof(fontmap
.fontface
));
662 found
= localbsearch(&fontmap
, fontlistMS
.fontmap
, fontlistMS
.len
, sizeof(pdf_fontmapMS
),compare
);
666 found
= findlinear(&fontlistMS
, &fontmap
);
671 *fontpath
= found
->fontpath
;
672 *index
= found
->index
;
676 *fontpath
= fontlistMS
.fontmap
[0].fontpath
;
677 *index
= fontlistMS
.fontmap
[0].index
;
683 static FT_Library ftlib
= nil
;
685 static fz_error
*initfontlibs(void)
694 fterr
= FT_Init_FreeType(&ftlib
);
696 return fz_throw("freetype failed initialisation: 0x%x", fterr
);
698 FT_Library_Version(ftlib
, &maj
, &min
, &pat
);
699 if (maj
== 2 && min
== 1 && pat
< 7)
700 return fz_throw("freetype version too old: %d.%d.%d", maj
, min
, pat
);
702 err
= pdf_createfontlistMS();
709 fz_error
*initfontlibs_ms(void)
711 return initfontlibs();
714 void deinitfontlibs_ms(void)
716 pdf_destoryfontlistMS();
717 FT_Done_FreeType(ftlib
);
722 pdf_loadbuiltinfont(pdf_font
*font
, char *basefont
)
731 error
= initfontlibs();
735 error
= pdf_lookupfontMS(basefont
,&file
,&index
);
739 fterr
= FT_New_Face(ftlib
, file
, index
, &face
);
741 return fz_throw("freetype could not load font file '%s': 0x%x", file
, fterr
);
749 pdf_loadsystemfont(pdf_font
*font
, char *basefont
, char *collection
)
757 error
= initfontlibs();
761 error
= pdf_lookupfontMS(basefont
,&file
,&index
);
765 fterr
= FT_New_Face(ftlib
, file
, index
, &face
);
767 return fz_throw("freetype could not load font file '%s': 0x%x", file
, fterr
);
779 pdf_loadembeddedfont(pdf_font
*font
, pdf_xref
*xref
, fz_obj
*stmref
)
786 error
= initfontlibs();
790 error
= pdf_loadstream(&buf
, xref
, fz_tonum(stmref
), fz_togen(stmref
));
794 fterr
= FT_New_Memory_Face(ftlib
, buf
->rp
, buf
->wp
- buf
->rp
, 0, &face
);
798 return fz_throw("freetype could not load embedded font: 0x%x", fterr
);
802 font
->fontdata
= buf
;