3 % Copyright
1996-2006 Han The Thanh
<thanh@@pdftex.org
>
4 % Copyright
2006-2010 Taco Hoekwater
<taco@@luatex.org
>
6 % This file is part of LuaTeX.
8 % LuaTeX is free software
; you can redistribute it and
/or modify it under
9 % the terms of the GNU General Public License as published by the Free
10 % Software Foundation
; either version
2 of the License
, or
(at your
11 % option
) any later version.
13 % LuaTeX is distributed in the hope that it will be useful
, but WITHOUT
14 % ANY WARRANTY
; without even the implied warranty of MERCHANTABILITY or
15 % FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 % License for more details.
18 % You should have received a copy of the GNU General Public License along
19 % with LuaTeX
; if not
, see
<http
://www.gnu.org
/licenses
/>.
26 #include
<kpathsea
/c-auto.h
>
27 #include
<kpathsea
/c-memstr.h
>
30 #define FM_BUF_SIZE
1024
34 static unsigned char
*fm_buffer
= NULL;
35 static int fm_size
= 0;
36 static int fm_curbyte
= 0;
38 #define fm_open
(a
) (fm_file
= fopen
((char
*)(a
), FOPEN_RBIN_MODE
))
39 #define fm_read_file
() readbinfile
(fm_file
,&fm_buffer,&fm_size)
40 #define fm_close
() xfclose
(fm_file
, cur_file_name
)
41 #define fm_getchar
() fm_buffer
[fm_curbyte
++]
42 #define fm_eof
() (fm_curbyte
>fm_size
)
43 #define is_cfg_comment
(c
) \
44 (c
== 10 || c
== '
*' || c
== '#' || c
== '
;' || c
== '
%'
)
46 typedef enum
{ FM_DUPIGNORE
, FM_REPLACE
, FM_DELETE
} updatemode
;
48 typedef struct mitem
{
49 updatemode mode
; /* FM_DUPIGNORE or FM_REPLACE or FM_DELETE
*/
50 maptype type
; /* map file or map line
*/
51 char
*line
; /* pointer to map file name or map line
*/
52 int lineno
; /* line number in map file
*/
54 mapitem
*mitem
= NULL;
56 #define read_field
(r
, q
, buf
) do
{ \
58 while
(*r
!= ' '
&& *r != '<' && *r != '"' && *r != '\0') \
64 #define set_field(F) do { \
66 fm->F = xstrdup(buf); \
71 fm_entry *new_fm_entry(void)
74 fm = xtalloc(1, fm_entry);
78 fm->fd_flags = FD_FLAGS_NOT_SET_IN_MAPLINE;
93 void delete_fm_entry(fm_entry * fm)
102 static ff_entry *new_ff_entry(void)
105 ff = xtalloc(1, ff_entry);
111 static void delete_ff_entry(ff_entry * ff)
118 /**********************************************************************/
120 static struct avl_table *tfm_tree = NULL;
121 static struct avl_table *ff_tree = NULL;
122 static struct avl_table *encname_tree = NULL;
124 /* AVL sort fm_entry into tfm_tree by tfm_name */
126 static int comp_fm_entry_tfm(const void *pa, const void *pb, void *p)
129 return strcmp(((const fm_entry *) pa)->tfm_name,
130 ((const fm_entry *) pb)->tfm_name);
133 /* AVL sort ff_entry into ff_tree by ff_name */
135 static int comp_ff_entry(const void *pa, const void *pb, void *p)
138 return strcmp(((const ff_entry *) pa)->ff_name,
139 ((const ff_entry *) pb)->ff_name);
142 static void create_avl_trees(void)
144 assert(tfm_tree == NULL);
145 tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator);
146 assert(tfm_tree != NULL);
147 assert(ff_tree == NULL);
148 ff_tree = avl_create(comp_ff_entry, NULL, &avl_xallocator);
149 assert(ff_tree != NULL);
150 assert(encname_tree == NULL);
151 encname_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
152 assert(encname_tree != NULL);
155 int avl_do_entry(fm_entry * fm, int mode)
161 if (tfm_tree == NULL)
163 p = (fm_entry *) avl_find(tfm_tree, fm);
167 formatted_warning("map file", "entry for '%s' already exists, duplicates ignored", fm->tfm_name);
173 formatted_warning("map file", "entry for '%s' has been used, replace/delete not allowed", fm->tfm_name);
176 a = avl_delete(tfm_tree, p);
185 if ((mode == FM_DUPIGNORE || mode == FM_REPLACE) && delete_new == 0) {
186 aa = avl_probe(tfm_tree, fm);
193 /* add the encoding name to an AVL tree. this has nothing to do with writeenc.c */
195 static char *add_encname(char *s)
200 assert(encname_tree != NULL);
201 if ((p = (char *) avl_find(encname_tree, s)) == NULL) { /* encoding name not yet registered */
203 aa = avl_probe(encname_tree, p);
209 /**********************************************************************/
210 /* consistency check for map entry, with warn flag */
212 static int check_fm_entry(fm_entry * fm, boolean warn)
217 if (is_fontfile(fm) && !is_included(fm)) {
219 formatted_warning("map file",
220 "ambiguous entry for '%s': font file present but not included, "
221 "will be treated as font file not present", fm->tfm_name);
223 /* do not set variable |a| as this entry will be still accepted */
226 /* if both ps_name and font file are missing, drop this entry */
227 if (fm->ps_name == NULL && !is_fontfile(fm)) {
229 formatted_warning("map file", "invalid entry for '%s': both ps_name and font file missing", fm->tfm_name);
233 /* TrueType fonts cannot be reencoded without subsetting */
234 if (is_truetype(fm) && is_reencoded(fm) && !is_subsetted(fm)) {
236 formatted_warning("map file", "invalid entry for '%s': only subsetted TrueType font can be reencoded", fm->tfm_name);
240 /* the value of SlantFont and ExtendFont must be reasonable */
241 if (fm->slant < FONT_SLANT_MIN || fm->slant > FONT_SLANT_MAX) {
243 formatted_warning("map file", "invalid entry for '%s': value '%g' is to large for SlantFont",
244 fm->tfm_name, fm->slant / 1000.0);
247 if (fm->extend < FONT_EXTEND_MIN || fm->extend > FONT_EXTEND_MAX) {
249 formatted_warning("map file", "invalid entry for '%s': value '%g' is too large for ExtendFont",
250 fm->tfm_name, fm->extend / 1000.0);
254 /* subfonts must be used with subsetted non-reencoded TrueType fonts */
256 !(is_truetype(fm) && is_subsetted(fm) && !is_reencoded(fm))) {
258 formatted_warning("map file", "invalid entry for '%s': PidEid can be used only with subsetted non-reencoded TrueType fonts",
266 /**********************************************************************/
267 /* returns the font number if s is one of the 14 std. font names, -1 otherwise; speed-trimmed. */
269 int check_std_t1font(char *s)
271 static const char *std_t1font_names[] = {
273 "Courier-Bold", /* 1:12 */
274 "Courier-Oblique", /* 2:15 */
275 "Courier-BoldOblique", /* 3:19 */
276 "Helvetica", /* 4:9 */
277 "Helvetica-Bold", /* 5:14 */
278 "Helvetica-Oblique", /* 6:17 */
279 "Helvetica-BoldOblique", /* 7:21 */
281 "Times-Roman", /* 9:11 */
282 "Times-Bold", /* 10:10 */
283 "Times-Italic", /* 11:12 */
284 "Times-BoldItalic", /* 12:16 */
285 "ZapfDingbats" /* 13:12 */
287 static const int index[] =
288 { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6, -1,
297 if (n == 12) { /* three names have length 12 */
300 k = 1; /* Courier-Bold */
303 k = 11; /* Times-Italic */
306 k = 13; /* ZapfDingbats */
313 if (k > -1 && !strcmp(std_t1font_names[k], s))
318 /**********************************************************************/
320 static void fm_scan_line(void)
322 int a, b, c, j, u = 0, v = 0;
326 char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
329 switch (mitem->type) {
333 if (fm_curbyte == fm_size) {
337 cc = (char) fm_getchar();
339 append_char_to_buf(cc, p, fm_line, FM_BUF_SIZE);
347 r = mitem->line; /* work on string from makecstring() */
352 if (*r == '\0' || is_cfg_comment(*r))
355 read_field(r, q, buf);
357 if (!isdigit((unsigned char)*r)) { /* 2nd field ps_name may not start with a digit */
358 read_field(r, q, buf);
361 if (isdigit((unsigned char)*r)) { /* font descriptor /Flags given? */
362 for (s = r; isdigit((unsigned char)*s); s++);
363 if (*s == ' ' || *s == '"' || *s == '<' || *s == '\0') { /* not e. g. 8r.enc */
364 fm-
>fd_flags
= atoi
(r
);
365 while
(isdigit
((unsigned char
)*r
))
369 while
(1) { /* loop through
"specials", encoding
, font file
*/
374 case '
"': /* opening quote */
379 if (sscanf(r, "%f
%n
", &d, &j) > 0) {
380 s = r + j; /* jump behind number, eat also blanks, if any */
381 if (*(s - 1) == 'E' || *(s - 1) == 'e')
382 s--; /* e. g. 0.5ExtendFont: %f = 0.5E */
383 if (str_prefix(s, "SlantFont
")) {
384 d *= (float) 1000.0; /* correct rounding also for neg. numbers */
385 fm->slant = (int) (d > 0 ? d + 0.5 : d - 0.5);
387 r = s + strlen("SlantFont
");
388 } else if (str_prefix(s, "ExtendFont
")) {
390 fm->extend = (int) (d > 0 ? d + 0.5 : d - 0.5);
392 r = s + strlen("ExtendFont
");
393 } else { /* unknown name */
394 for (r = s; *r != ' ' && *r != '"'
&& *r != '\0'; r++); /* jump over name */
395 c
= *r
; /* remember char for temporary end of string
*/
397 formatted_warning
("map file", "invalid entry for '%s': unknown name '%s' ignored", fm-
>tfm_name
, s
);
401 for
(; *r
!= ' '
&& *r != '"' && *r != '\0'; r++);
404 if (*r == '"') /* closing quote */
407 formatted_warning
("map file", "invalid entry for '%s': closing quote missing", fm-
>tfm_name
);
411 case 'P'
: /* handle cases for subfonts like 'PidEid
=3,1'
*/
412 if
(sscanf
(r
, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
418 default
: /* encoding or font file specification
*/
422 if
(*r
== '
<' ||
*r
== '
['
)
425 read_field
(r
, q
, buf
);
426 /* encoding
, formats
: '
8r.enc' or '
<8r.enc' or '
<[8r.enc'
*/
427 if
(strlen
(buf
) > 4 && strcasecmp(strend(buf) - 4, ".enc") == 0) {
428 fm-
>encname
= add_encname
(buf
);
429 u
= v
= 0; /* u
, v used if intervening blank
: "<< foo" */
430 } else if
(strlen
(buf
) > 0) { /* file name given
*/
431 /* font file
, formats
:
432 * subsetting
: '
<cmr10.pfa'
433 * no subsetting
: '
<<cmr10.pfa'
434 * no embedding
: 'cmr10.pfa'
436 if
(a
== '
<' || u
== '
<'
) {
438 if
((a
== '
<'
&& b == 0) || (a == 0 && v == 0))
440 /* otherwise b
== '
<'
(or '
['
) => no subsetting
*/
451 if
(fm-
>ps_name
!= NULL && (check_std_t1font(fm->ps_name) >= 0))
453 if
(is_fontfile
(fm
) && strlen(fm_fontfile(fm)) > 3) {
454 if
(strcasecmp
(strend
(fm_fontfile
(fm
)) - 4, ".ttf") == 0)
456 else if
(strcasecmp
(strend
(fm_fontfile
(fm
)) - 4, ".ttc") == 0)
458 else if
(strcasecmp
(strend
(fm_fontfile
(fm
)) - 4, ".otf") == 0)
463 set_type1
(fm
); /* assume a builtin font is Type1
*/
464 if
(check_fm_entry
(fm
, true
) != 0)
467 Until here the map line has been completely scanned without errors
;
468 fm points to a valid
, freshly filled-out fm_entry structure.
469 Now follows the actual work of registering
/deleting.
471 if
(handle_subfont_fm
(fm
, mitem-
>mode
)) /* is this a subfont?
*/
473 if
(avl_do_entry
(fm
, mitem-
>mode
) == 0)
479 /**********************************************************************/
481 static void fm_read_info
(void
)
486 if
(tfm_tree
== NULL)
488 if
(mitem-
>line
== NULL) /* nothing to do
*/
491 switch
(mitem-
>type
) {
496 cur_file_name
= luatex_find_file
(mitem-
>line
, find_map_file_callback
);
498 callback_id
= callback_defined
(read_map_file_callback
);
499 if
(callback_id
> 0) {
500 if
(run_callback
(callback_id
, "S->bSd", cur_file_name
,
501 &file_opened, &fm_buffer, &fm_size)) {
504 report_start_file
(filetype_map
,cur_file_name
);
509 report_stop_file
(filetype_map
);
513 formatted_warning
("map file", "cannot open font map file '%s'", cur_file_name
);
516 formatted_warning
("map file", "cannot open font map file '%s'", cur_file_name
);
519 if
(!fm_open
(cur_file_name
)) {
520 formatted_warning
("map file", "cannot open font map file '%s'", cur_file_name
);
523 report_start_file
(filetype_map
,cur_file_name
);
529 report_stop_file
(filetype_map
);
533 cur_file_name
= NULL;
537 cur_file_name
= NULL;
543 mitem-
>line
= NULL; /* done with this line
*/
544 cur_file_name
= NULL;
548 /**********************************************************************/
550 fm_entry
*getfontmap
(char
*tfm_name
)
554 if
(tfm_name
== NULL) /* wide
, lua loaded fonts may not have a name
*/
556 if
(tfm_tree
== NULL)
557 fm_read_info
(); /* only to read default map file
*/
558 tmp.tfm_name
= tfm_name
; /* Look up for tfmname
*/
559 fm
= (fm_entry
*) avl_find
(tfm_tree
, &tmp);
566 /**********************************************************************/
568 * Process map file given by its name or map line contents. Items not
569 * beginning with
[+-=] flush default map file
, if it has not yet been
570 * read. Leading blanks and blanks immediately following
[+-=] are
574 void process_map_item
(char
*s
, int type
)
579 s
++; /* ignore leading blank
*/
581 case '
+'
: /* +mapfile.map
, +mapline
*/
582 mode
= FM_DUPIGNORE
; /* insert entry
, if it is not duplicate
*/
585 case '
='
: /* =mapfile.map
, =mapline
*/
586 mode
= FM_REPLACE
; /* try to replace earlier entry
*/
589 case '
-'
: /* -mapfile.map
, -mapline
*/
590 mode
= FM_DELETE
; /* try to delete entry
*/
594 mode
= FM_DUPIGNORE
; /* like
+, but also
: */
595 mitem-
>line
= NULL; /* flush default map file name
*/
598 s
++; /* ignore blank after
[+-=] */
599 p
= s
; /* map item starts here
*/
601 case MAPFILE
: /* remove blank at end
*/
602 while
(*p
!= '\
0'
&& *p != ' ')
606 case MAPLINE
: /* blank at end allowed
*/
611 if
(mitem-
>line
!= NULL) /* read default map file first
*/
613 if
(*s
!= '\
0'
) { /* only if real item to process
*/
621 void pdfmapfile
(int t
)
623 char
*s
= tokenlist_to_cstring
(t
, true
, NULL);
624 process_map_item
(s
, MAPFILE
);
628 void pdfmapline
(int t
)
630 char
*s
= tokenlist_to_cstring
(t
, true
, NULL);
631 process_map_item
(s
, MAPLINE
);
635 void pdf_init_map_file
(char
*map_name
)
637 assert
(mitem
== NULL);
638 mitem
= xtalloc
(1, mapitem
);
639 mitem-
>mode
= FM_DUPIGNORE
;
640 mitem-
>type
= MAPFILE
;
641 mitem-
>line
= map_name
;
644 /**********************************************************************/
646 * Early check whether a font file exists. Search tree ff_tree is used
647 * in
1st instance
, as it may be faster than the kpse_find_file
(), and
648 * kpse_find_file
() is called only once per font file name
+ expansion
649 * parameter. This might help keeping speed
, if many PDF pages with
650 * same fonts are to be embedded.
652 * The ff_tree contains only font files
, which are actually needed
,
653 * so this tree typically is much smaller than the tfm_tree.
656 ff_entry
*check_ff_exist
(char
*ff_name
, boolean is_tt
)
662 char
*filepath
= NULL;
664 assert
(ff_name
!= NULL);
665 tmp.ff_name
= ff_name
;
666 ff
= (ff_entry
*) avl_find
(ff_tree
, &tmp);
667 if
(ff
== NULL) { /* not yet in database
*/
669 ff-
>ff_name
= xstrdup
(ff_name
);
671 callback_id
= callback_defined
(find_truetype_file_callback
);
672 if
(callback_id
> 0) {
673 run_callback
(callback_id
, "S->S", ff_name
, &filepath);
674 if
(filepath
&& strlen(filepath) == 0)
676 ff-
>ff_path
= filepath
;
678 ff-
>ff_path
= kpse_find_file
(ff_name
, kpse_truetype_format
, 0);
681 callback_id
= callback_defined
(find_type1_file_callback
);
682 if
(callback_id
> 0) {
683 run_callback
(callback_id
, "S->S", ff_name
, &filepath);
684 if
(filepath
&& strlen(filepath) == 0)
686 ff-
>ff_path
= filepath
;
688 ff-
>ff_path
= kpse_find_file
(ff_name
, kpse_type1_format
, 0);
691 aa
= avl_probe
(ff_tree
, ff
);
697 /**********************************************************************/
699 int is_subsetable
(fm_entry
* fm
)
701 assert
(is_included
(fm
));
702 return is_subsetted
(fm
);
705 /**********************************************************************/
708 static void destroy_fm_entry_tfm
(void
*pa
, void
*pb
)
712 fm
= (fm_entry
*) pa
;
716 static void destroy_ff_entry
(void
*pa
, void
*pb
)
720 ff
= (ff_entry
*) pa
;
726 if
(tfm_tree
!= NULL) {
727 avl_destroy
(tfm_tree
, destroy_fm_entry_tfm
);
730 if
(ff_tree
!= NULL) {
731 avl_destroy
(ff_tree
, destroy_ff_entry
);