1
/* $Header: /home/cvsroot/dvipdfmx/src/fontmap.c,v 1.43 2011/03/06 03:14:14 chofchof Exp $
3
This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5
Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
6
the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
8
Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
41
static char *strip_options (const char *map_name, fontmap_opt *opt);
43
static int verbose = 0;
45
pdf_fontmap_set_verbose (void)
52
pdf_init_fontmap_record (fontmap_rec *mrec)
56
mrec->map_name = NULL;
58
/* SFD char mapping */
59
mrec->charmap.sfd_name = NULL;
60
mrec->charmap.subfont_id = NULL;
62
mrec->opt.mapc = -1; /* compatibility */
64
mrec->font_name = NULL;
65
mrec->enc_name = NULL;
67
mrec->opt.slant = 0.0;
68
mrec->opt.extend = 1.0;
73
mrec->opt.design_size = -1.0;
75
mrec->opt.tounicode = NULL;
76
mrec->opt.otl_tags = NULL; /* deactivated */
78
mrec->opt.charcoll = NULL;
79
mrec->opt.style = FONTMAP_STYLE_NONE;
80
mrec->opt.stemv = -1; /* not given explicitly by an option */
84
pdf_clear_fontmap_record (fontmap_rec *mrec)
89
RELEASE(mrec->map_name);
90
if (mrec->charmap.sfd_name)
91
RELEASE(mrec->charmap.sfd_name);
92
if (mrec->charmap.subfont_id)
93
RELEASE(mrec->charmap.subfont_id);
95
RELEASE(mrec->enc_name);
97
RELEASE(mrec->font_name);
99
if (mrec->opt.tounicode)
100
RELEASE(mrec->opt.tounicode);
101
if (mrec->opt.otl_tags)
102
RELEASE(mrec->opt.otl_tags);
103
if (mrec->opt.charcoll)
104
RELEASE(mrec->opt.charcoll);
105
pdf_init_fontmap_record(mrec);
108
/* strdup: just returns NULL for NULL */
110
mstrdup (const char *s)
115
r = NEW(strlen(s) + 1, char);
121
pdf_copy_fontmap_record (fontmap_rec *dst, const fontmap_rec *src)
123
ASSERT( dst && src );
125
dst->map_name = mstrdup(src->map_name);
127
dst->charmap.sfd_name = mstrdup(src->charmap.sfd_name);
128
dst->charmap.subfont_id = mstrdup(src->charmap.subfont_id);
130
dst->font_name = mstrdup(src->font_name);
131
dst->enc_name = mstrdup(src->enc_name);
133
dst->opt.slant = src->opt.slant;
134
dst->opt.extend = src->opt.extend;
135
dst->opt.bold = src->opt.bold;
137
dst->opt.flags = src->opt.flags;
138
dst->opt.mapc = src->opt.mapc;
140
dst->opt.tounicode = mstrdup(src->opt.tounicode);
141
dst->opt.otl_tags = mstrdup(src->opt.otl_tags);
142
dst->opt.index = src->opt.index;
143
dst->opt.charcoll = mstrdup(src->opt.charcoll);
144
dst->opt.style = src->opt.style;
145
dst->opt.stemv = src->opt.stemv;
152
fontmap_rec *mrec = (fontmap_rec *) vp;
153
pdf_clear_fontmap_record(mrec);
159
fill_in_defaults (fontmap_rec *mrec, const char *tex_name)
161
if (mrec->enc_name &&
162
(!strcmp(mrec->enc_name, "default") ||
163
!strcmp(mrec->enc_name, "none"))) {
164
RELEASE(mrec->enc_name);
165
mrec->enc_name = NULL;
167
if (mrec->font_name &&
168
(!strcmp(mrec->font_name, "default") ||
169
!strcmp(mrec->font_name, "none"))) {
170
RELEASE(mrec->font_name);
171
mrec->font_name = NULL;
173
/* We *must* fill font_name either explicitly or by default */
174
if (!mrec->font_name) {
175
mrec->font_name = NEW(strlen(tex_name)+1, char);
176
strcpy(mrec->font_name, tex_name);
179
mrec->map_name = NEW(strlen(tex_name)+1, char);
180
strcpy(mrec->map_name, tex_name);
182
#ifndef WITHOUT_COMPAT
183
/* Use "UCS" character collection for Unicode SFD
184
* and Identity CMap combination. For backward
187
if (mrec->charmap.sfd_name && mrec->enc_name &&
188
!mrec->opt.charcoll) {
189
if ((!strcmp(mrec->enc_name, "Identity-H") ||
190
!strcmp(mrec->enc_name, "Identity-V"))
192
(strstr(mrec->charmap.sfd_name, "Uni") ||
193
strstr(mrec->charmap.sfd_name, "UBig") ||
194
strstr(mrec->charmap.sfd_name, "UBg") ||
195
strstr(mrec->charmap.sfd_name, "UGB") ||
196
strstr(mrec->charmap.sfd_name, "UKS") ||
197
strstr(mrec->charmap.sfd_name, "UJIS"))) {
198
mrec->opt.charcoll = NEW(strlen("UCS")+1, char);
199
strcpy(mrec->opt.charcoll, "UCS");
202
#endif /* WITHOUT_COMPAT */
208
readline (char *buf, int buf_len, FILE *fp)
211
ASSERT( buf && buf_len > 0 && fp );
212
p = mfgets(buf, buf_len, fp);
215
q = strchr(p, '%'); /* we don't have quoted string */
222
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
225
skip_blank (const char **pp, const char *endptr)
228
if (!p || p >= endptr)
230
for ( ; p < endptr && ISBLANK(*p); p++);
235
parse_string_value (const char **pp, const char *endptr)
241
if (!p || p >= endptr)
244
q = parse_c_string(&p, endptr);
246
for (n = 0; p < endptr && !isspace(*p); p++, n++);
249
q = NEW(n + 1, char);
250
memcpy(q, *pp, n); q[n] = '\0';
257
/* no preceeding spaces allowed */
259
parse_integer_value (const char **pp, const char *endptr, int base)
263
int has_sign = 0, has_prefix = 0, n;
265
ASSERT( base == 0 || (base >= 2 && base <= 36) );
267
if (!p || p >= endptr)
270
if (*p == '-' || *p == '+') {
273
if ((base == 0 || base == 16) &&
275
p[0] == '0' && p[1] == 'x') {
276
p += 2; has_prefix = 1;
281
else if (p < endptr && *p == '0')
287
#define ISDIGIT_WB(c,b) ( \
288
((b) <= 10 && (c) >= '0' && (c) < '0' + (b)) || \
290
((c) >= '0' && (c) <= '9') || \
291
((c) >= 'a' && (c) < 'a' + ((b) - 10)) || \
292
((c) >= 'A' && (c) < 'A' + ((b) - 10)) \
296
for (n = 0; p < endptr && ISDIGIT_WB(*p, base); p++, n++);
304
q = NEW(n + 1, char);
305
memcpy(q, *pp, n); q[n] = '\0';
312
fontmap_parse_mapdef_dpm (fontmap_rec *mrec,
313
const char *mapdef, const char *endptr)
315
const char *p = mapdef;
318
* Parse record line in map file. First two fields (after TeX font
319
* name) are position specific. Arguments start at the first token
320
* beginning with a '-'.
323
* Dvipdfm basically uses parse_ident() for parsing enc_name,
324
* font_name, and other string values which assumes PostScript-like
326
* skip_white() skips '\r' and '\n' but they should terminate
330
skip_blank(&p, endptr);
332
if (p < endptr && *p != '-') { /* May be NULL */
333
mrec->enc_name = parse_string_value(&p, endptr);
334
skip_blank(&p, endptr);
337
/* fontname or font filename field */
338
if (p < endptr && *p != '-') { /* May be NULL */
339
mrec->font_name = parse_string_value(&p, endptr);
340
skip_blank(&p, endptr);
342
if (mrec->font_name) {
344
/* Several options are encoded in font_name for
345
* compatibility with dvipdfm.
347
tmp = strip_options(mrec->font_name, &mrec->opt);
349
RELEASE(mrec->font_name);
350
mrec->font_name = tmp;
354
skip_blank(&p, endptr);
355
/* Parse any remaining arguments */
356
while (p + 1 < endptr &&
357
*p != '\r' && *p != '\n' && *p == '-') {
358
char *q, mopt = p[1];
361
p += 2; skip_blank(&p, endptr);
364
case 's': /* Slant option */
365
q = parse_float_decimal(&p, endptr);
367
WARN("Missing a number value for 's' option.");
370
mrec->opt.slant = atof(q);
374
case 'e': /* Extend option */
375
q = parse_float_decimal(&p, endptr);
377
WARN("Missing a number value for 'e' option.");
380
mrec->opt.extend = atof(q);
381
if (mrec->opt.extend <= 0.0) {
382
WARN("Invalid value for 'e' option: %s", q);
388
case 'b': /* Fake-bold option */
389
q = parse_float_decimal(&p, endptr);
391
WARN("Missing a number value for 'b' option.");
394
mrec->opt.bold = atof(q);
395
if (mrec->opt.bold <= 0.0) {
396
WARN("Invalid value for 'b' option: %s", q);
402
case 'r': /* Remap option; obsolete; just ignore */
405
case 'i': /* TTC index */
406
q = parse_integer_value(&p, endptr, 10);
408
WARN("Missing TTC index number...");
411
mrec->opt.index = atoi(q);
412
if (mrec->opt.index < 0) {
413
WARN("Invalid TTC index number: %s", q);
419
case 'p': /* UCS plane: just for testing */
420
q = parse_integer_value(&p, endptr, 0);
422
WARN("Missing a number for 'p' option.");
425
v = strtol(q, NULL, 0);
427
WARN("Invalid value for option 'p': %s", q);
429
mrec->opt.mapc = v << 16;
434
case 'u': /* ToUnicode */
435
q = parse_string_value(&p, endptr);
437
mrec->opt.tounicode = q;
439
WARN("Missing string value for option 'u'.");
444
case 'v': /* StemV */
445
q = parse_integer_value(&p, endptr, 10);
447
WARN("Missing a number for 'v' option.");
450
mrec->opt.stemv = strtol(q, NULL, 0);
454
/* Omega uses both single-byte and double-byte set_char command
455
* even for double-byte OFMs. This confuses CMap decoder.
458
/* Map single bytes char 0xab to double byte char 0xcdab */
459
if (p + 4 <= endptr &&
460
p[0] == '<' && p[3] == '>') {
462
q = parse_integer_value(&p, endptr, 16);
464
WARN("Invalid value for option 'm'.");
466
} else if (p < endptr && *p != '>') {
467
WARN("Invalid value for option 'm': %s", q);
471
v = strtol(q, NULL, 16);
472
mrec->opt.mapc = ((v << 8) & 0x0000ff00L);
474
} else if (p + 4 <= endptr &&
475
!memcmp(p, "sfd:", strlen("sfd:"))) {
477
/* SFD mapping: sfd:Big5,00 */
478
p += 4; skip_blank(&p, endptr);
479
q = parse_string_value(&p, endptr);
481
WARN("Missing value for option 'm'.");
486
WARN("Invalid value for option 'm': %s", q);
490
*r = 0; r++; skip_blank((const char **)&r, r + strlen(r));
492
WARN("Invalid value for option 'm': %s,", q);
496
mrec->charmap.sfd_name = mstrdup(q);
497
mrec->charmap.subfont_id = mstrdup(r);
499
} else if (p + 4 < endptr &&
500
!memcmp(p, "pad:", strlen("pad:"))) {
501
p += 4; skip_blank(&p, endptr);
502
q = parse_integer_value(&p, endptr, 16);
504
WARN("Invalid value for option 'm'.");
506
} else if (p < endptr && !isspace(*p)) {
507
WARN("Invalid value for option 'm': %s", q);
511
v = strtol(q, NULL, 16);
512
mrec->opt.mapc = ((v << 8) & 0x0000ff00L);
515
WARN("Invalid value for option 'm'.");
520
case 'w': /* Writing mode (for unicode encoding) */
521
if (!mrec->enc_name ||
522
strcmp(mrec->enc_name, "unicode")) {
523
WARN("Fontmap option 'w' meaningless for encoding other than \"unicode\".");
526
q = parse_integer_value(&p, endptr, 10);
528
WARN("Missing wmode value...");
532
mrec->opt.flags |= FONTMAP_OPT_VERT;
533
else if (atoi(q) == 0)
534
mrec->opt.flags &= ~FONTMAP_OPT_VERT;
536
WARN("Invalid value for option 'w': %s", q);
542
WARN("Unrecognized font map option: '%c'", mopt);
546
skip_blank(&p, endptr);
549
if (p < endptr && *p != '\r' && *p != '\n') {
550
WARN("Invalid char in fontmap line: %c", *p);
558
/* Parse record line in map file of DVIPS/pdfTeX format. */
560
fontmap_parse_mapdef_dps (fontmap_rec *mrec,
561
const char *mapdef, const char *endptr)
563
const char *p = mapdef;
566
skip_blank(&p, endptr);
568
/* The first field (after TFM name) must be PostScript name. */
569
/* However, pdftex.map allows a line without PostScript name. */
571
if (*p != '"' && *p != '<') {
573
q = parse_string_value(&p, endptr);
575
skip_blank(&p, endptr);
577
WARN("Missing a PostScript font name.");
582
if (p >= endptr) return 0;
584
/* Parse any remaining arguments */
585
while (p < endptr && *p != '\r' && *p != '\n' && (*p == '<' || *p == '"')) {
587
case '<': /* encoding or fontfile field */
588
if (++p < endptr && *p == '[') p++; /*skip */
589
skip_blank(&p, endptr);
590
if ((q = parse_string_value(&p, endptr))) {
592
if (n > 4 && strncmp(q+n-4, ".enc", 4) == 0)
597
skip_blank(&p, endptr);
600
case '"': /* Options */
601
if ((q = parse_string_value(&p, endptr))) {
602
const char *r = q, *e = q+strlen(q);
606
if ((s = parse_float_decimal(&r, e))) {
608
if ((t = parse_string_value(&r, e))) {
609
if (strcmp(t, "SlantFont") == 0)
610
mrec->opt.slant = atof(s);
611
else if (strcmp(t, "ExtendFont") == 0)
612
mrec->opt.extend = atof(s);
616
} else if ((s = parse_string_value(&r, e))) { /* skip */
623
skip_blank(&p, endptr);
627
WARN("Found an invalid entry: %s", p);
631
skip_blank(&p, endptr);
634
if (p < endptr && *p != '\r' && *p != '\n') {
635
WARN("Invalid char in fontmap line: %c", *p);
643
static struct ht_table *fontmap = NULL;
645
#define fontmap_invalid(m) (!(m) || !(m)->map_name || !(m)->font_name)
647
chop_sfd_name (const char *tex_name, char **sfd_name)
655
p = strchr(tex_name, '@');
657
p[1] == '\0' || p == tex_name) {
660
m = (int) (p - tex_name);
669
len = strlen(tex_name) - n;
670
fontname = NEW(len+1, char);
671
memcpy(fontname, tex_name, m);
676
*sfd_name = NEW(n+1, char);
677
memcpy(*sfd_name, p, n);
678
(*sfd_name)[n] = '\0';
684
make_subfont_name (const char *map_name, const char *sfd_name, const char *sub_id)
690
p = strchr(map_name, '@');
691
if (!p || p == map_name)
693
m = (int) (p - map_name);
694
q = strchr(p + 1, '@');
695
if (!q || q == p + 1)
697
n = (int) (q - p) + 1; /* including two '@' */
698
if (strlen(sfd_name) != n - 2 ||
699
memcmp(p + 1, sfd_name, n - 2))
701
tfm_name = NEW(strlen(map_name) - n + strlen(sub_id) + 1, char);
702
memcpy(tfm_name, map_name, m);
704
strcat(tfm_name, sub_id);
705
if (q[1]) /* not ending with '@' */
706
strcat(tfm_name, q + 1);
711
/* "foo@A@ ..." is expanded to
712
* fooab ... -m sfd:A,ab
714
* fooyz ... -m sfd:A,yz
715
* where 'ab' ... 'yz' is subfont IDs in SFD 'A'.
718
pdf_append_fontmap_record (const char *kp, const fontmap_rec *vp)
721
char *fnt_name, *sfd_name = NULL;
723
if (!kp || fontmap_invalid(vp)) {
724
WARN("Invalid fontmap record...");
729
MESG("fontmap>> append key=\"%s\"...", kp);
731
fnt_name = chop_sfd_name(kp, &sfd_name);
732
if (fnt_name && sfd_name) {
736
subfont_ids = sfd_get_subfont_ids(sfd_name, &n);
740
tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]);
743
mrec = ht_lookup_table(fontmap, tfm_name, strlen(tfm_name));
745
mrec = NEW(1, fontmap_rec);
746
pdf_init_fontmap_record(mrec);
747
mrec->map_name = mstrdup(kp); /* link */
748
mrec->charmap.sfd_name = mstrdup(sfd_name);
749
mrec->charmap.subfont_id = mstrdup(subfont_ids[n]);
750
ht_insert_table(fontmap, tfm_name, strlen(tfm_name), mrec);
758
mrec = ht_lookup_table(fontmap, kp, strlen(kp));
760
mrec = NEW(1, fontmap_rec);
761
pdf_copy_fontmap_record(mrec, vp);
762
if (mrec->map_name && !strcmp(kp, mrec->map_name)) {
763
RELEASE(mrec->map_name);
764
mrec->map_name = NULL;
766
ht_insert_table(fontmap, kp, strlen(kp), mrec);
775
pdf_remove_fontmap_record (const char *kp)
777
char *fnt_name, *sfd_name = NULL;
783
MESG("fontmap>> remove key=\"%s\"...", kp);
785
fnt_name = chop_sfd_name(kp, &sfd_name);
786
if (fnt_name && sfd_name) {
790
subfont_ids = sfd_get_subfont_ids(sfd_name, &n);
794
MESG("\nfontmap>> Expand @%s@:", sfd_name);
796
tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]);
800
MESG(" %s", tfm_name);
801
ht_remove_table(fontmap, tfm_name, strlen(tfm_name));
808
ht_remove_table(fontmap, kp, strlen(kp));
817
pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp)
820
char *fnt_name, *sfd_name;
822
if (!kp || fontmap_invalid(vp)) {
823
WARN("Invalid fontmap record...");
828
MESG("fontmap>> insert key=\"%s\"...", kp);
830
fnt_name = chop_sfd_name(kp, &sfd_name);
831
if (fnt_name && sfd_name) {
835
subfont_ids = sfd_get_subfont_ids(sfd_name, &n);
842
MESG("\nfontmap>> Expand @%s@:", sfd_name);
844
tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]);
848
MESG(" %s", tfm_name);
849
mrec = NEW(1, fontmap_rec);
850
pdf_init_fontmap_record(mrec);
851
mrec->map_name = mstrdup(kp); /* link to this entry */
852
mrec->charmap.sfd_name = mstrdup(sfd_name);
853
mrec->charmap.subfont_id = mstrdup(subfont_ids[n]);
854
ht_insert_table(fontmap, tfm_name, strlen(tfm_name), mrec);
861
mrec = NEW(1, fontmap_rec);
862
pdf_copy_fontmap_record(mrec, vp);
863
if (mrec->map_name && !strcmp(kp, mrec->map_name)) {
864
RELEASE(mrec->map_name);
865
mrec->map_name = NULL;
867
ht_insert_table(fontmap, kp, strlen(kp), mrec);
877
pdf_read_fontmap_line (fontmap_rec *mrec, const char *mline, long mline_len, int format)
881
const char *p, *endptr;
886
endptr = p + mline_len;
888
skip_blank(&p, endptr);
892
q = parse_string_value(&p, endptr);
896
if (format > 0) /* DVIPDFM format */
897
error = fontmap_parse_mapdef_dpm(mrec, p, endptr);
898
else /* DVIPS/pdfTeX format */
899
error = fontmap_parse_mapdef_dps(mrec, p, endptr);
901
char *fnt_name, *sfd_name = NULL;
902
fnt_name = chop_sfd_name(q, &sfd_name);
903
if (fnt_name && sfd_name) {
904
if (!mrec->font_name) {
905
/* In the case of subfonts, the base name (before the character '@')
906
* will be used as a font_name by default.
907
* Otherwise tex_name will be used as a font_name by default.
909
mrec->font_name = fnt_name;
913
if (mrec->charmap.sfd_name)
914
RELEASE(mrec->charmap.sfd_name);
915
mrec->charmap.sfd_name = sfd_name ;
917
fill_in_defaults(mrec, q);
924
/* DVIPS/pdfTeX fontmap line if one of the following three cases found:
926
* (1) any line including the character '"'
927
* (2) any line including the character '<'
928
* (3) if the line consists of two entries (tfmname and psname)
930
* DVIPDFM fontmap line otherwise.
933
is_pdfm_mapline (const char *mline) /* NULL terminated. */
936
const char *p, *endptr;
938
if (strchr(mline, '"') || strchr(mline, '<'))
939
return -1; /* DVIPS/pdfTeX format */
942
endptr = p + strlen(mline);
944
skip_blank(&p, endptr);
947
/* Break if '-' preceeded by blanks is found. (DVIPDFM format) */
948
if (*p == '-') return 1;
949
for (n++; p < endptr && !ISBLANK(*p); p++);
950
skip_blank(&p, endptr);
953
/* Two entries: TFM_NAME PS_NAME only (DVIPS format)
954
* Otherwise (DVIPDFM format) */
955
return (n == 2 ? 0 : 1);
959
pdf_load_fontmap_file (const char *filename, int mode)
963
const char *p = NULL, *endptr;
965
int error = 0, format = 0;
971
MESG("<FONTMAP:%s", filename);
973
fp = DPXFOPEN(filename, DPX_RES_TYPE_FONTMAP);
975
WARN("Couldn't open font map file \"%s\".", filename);
980
(p = readline(work_buffer, WORK_BUFFER_SIZE, fp)) != NULL) {
984
llen = strlen(work_buffer);
987
skip_blank(&p, endptr);
991
m = is_pdfm_mapline(p);
993
if (format * m < 0) { /* mismatch */
994
WARN("Found a mismatched fontmap line %d from %s.", lpos, filename);
995
WARN("-- Ignore the current input buffer: %s", p);
1000
mrec = NEW(1, fontmap_rec);
1001
pdf_init_fontmap_record(mrec);
1003
/* format > 0: DVIPDFM, format <= 0: DVIPS/pdfTeX */
1004
error = pdf_read_fontmap_line(mrec, p, llen, format);
1006
WARN("Invalid map record in fontmap line %d from %s.", lpos, filename);
1007
WARN("-- Ignore the current input buffer: %s", p);
1008
pdf_clear_fontmap_record(mrec);
1013
case FONTMAP_RMODE_REPLACE:
1014
pdf_insert_fontmap_record(mrec->map_name, mrec);
1016
case FONTMAP_RMODE_APPEND:
1017
pdf_append_fontmap_record(mrec->map_name, mrec);
1019
case FONTMAP_RMODE_REMOVE:
1020
pdf_remove_fontmap_record(mrec->map_name);
1024
pdf_clear_fontmap_record(mrec);
1036
/* tfm_name="dmjhira10", map_name="dmj@DNP@10", sfd_name="DNP"
1038
* Test if tfm_name can be really considered as subfont.
1041
test_subfont (const char *tfm_name, const char *map_name, const char *sfd_name)
1046
char *p = (char *) map_name;
1047
char *q = (char *) tfm_name;
1049
ASSERT( tfm_name && map_name && sfd_name );
1051
/* until first occurence of '@' */
1052
for ( ; *p && *q && *p == *q && *p != '@'; p++, q++);
1056
/* compare sfd_name (should be always true here) */
1057
if (strlen(p) <= strlen(sfd_name) ||
1058
memcmp(p, sfd_name, strlen(sfd_name)) ||
1059
p[strlen(sfd_name)] != '@')
1061
/* check tfm_name follows second '@' */
1062
p += strlen(sfd_name) + 1;
1064
char *r = (char *) tfm_name;
1065
r += strlen(tfm_name) - strlen(p);
1069
/* Now 'p' is located at next to SFD name terminator
1070
* (second '@') in map_name and 'q' is at first char
1071
* of subfont_id substring in tfm_name.
1073
n = strlen(q) - strlen(p); /* length of subfont_id string */
1076
/* check if n-length substring 'q' is valid as subfont ID */
1077
ids = sfd_get_subfont_ids(sfd_name, &m);
1080
while (!r && m-- > 0) {
1081
if (strlen(ids[m]) == n &&
1082
!memcmp(q, ids[m], n)) {
1093
pdf_lookup_fontmap_record (const char *tfm_name)
1095
fontmap_rec *mrec = NULL;
1097
if (fontmap && tfm_name)
1098
mrec = ht_lookup_table(fontmap, tfm_name, strlen(tfm_name));
1105
pdf_init_fontmaps (void)
1107
fontmap = NEW(1, struct ht_table);
1108
ht_init_table(fontmap, hval_free);
1112
pdf_close_fontmaps (void)
1115
ht_clear_table(fontmap);
1120
release_sfd_record();
1125
pdf_clear_fontmaps (void)
1127
pdf_close_fontmaps();
1128
pdf_init_fontmaps();
1136
* (:int:)?!?string(/string)?(,string)?
1140
substr (const char **str, char stop)
1145
endptr = strchr(*str, stop);
1146
if (!endptr || endptr == *str)
1148
sstr = NEW(endptr-(*str)+1, char);
1149
memcpy(sstr, *str, endptr-(*str));
1150
sstr[endptr-(*str)] = '\0';
1157
#define CID_MAPREC_CSI_DELIM '/'
1160
strip_options (const char *map_name, fontmap_opt *opt)
1165
int have_csi = 0, have_style = 0;
1171
opt->charcoll = NULL;
1173
opt->style = FONTMAP_STYLE_NONE;
1176
if (*p == ':' && isdigit(*(p+1))) {
1177
opt->index = (int) strtoul(p+1, &next, 10);
1184
if (*p == '!') { /* no-embedding */
1186
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1187
opt->flags |= FONTMAP_OPT_NOEMBED;
1190
if ((next = strchr(p, CID_MAPREC_CSI_DELIM)) != NULL) {
1192
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1193
font_name = substr(&p, CID_MAPREC_CSI_DELIM);
1195
} else if ((next = strchr(p, ',')) != NULL) {
1197
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1198
font_name = substr(&p, ',');
1201
font_name = NEW(strlen(p)+1, char);
1202
strcpy(font_name, p);
1206
if ((next = strchr(p, ',')) != NULL) {
1207
opt->charcoll = substr(&p, ',');
1209
} else if (p[0] == '\0') {
1210
ERROR("Invalid map record: %s.", map_name);
1212
opt->charcoll = NEW(strlen(p)+1, char);
1213
strcpy(opt->charcoll, p);
1218
if (!strncmp(p, "BoldItalic", 10)) {
1220
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1221
opt->style = FONTMAP_STYLE_BOLDITALIC;
1222
} else if (!strncmp(p, "Bold", 4)) {
1224
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1225
opt->style = FONTMAP_STYLE_BOLD;
1226
} else if (!strncmp(p, "Italic", 6)) {
1228
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1229
opt->style = FONTMAP_STYLE_ITALIC;
1238
dump_fontmap_rec (const char *key, const fontmap_rec *mrec)
1240
fontmap_opt *opt = (fontmap_opt *) &mrec->opt;
1243
fprintf(stdout, " <!-- subfont");
1245
fprintf(stdout, " <insert");
1246
fprintf(stdout, " id=\"%s\"", key);
1248
fprintf(stdout, " map-name=\"%s\"", mrec->map_name);
1250
fprintf(stdout, " enc-name=\"%s\"", mrec->enc_name);
1251
if (mrec->font_name)
1252
fprintf(stdout, " font-name=\"%s\"", mrec->font_name);
1253
if (mrec->charmap.sfd_name && mrec->charmap.subfont_id) {
1254
fprintf(stdout, " charmap=\"sfd:%s,%s\"",
1255
mrec->charmap.sfd_name, mrec->charmap.subfont_id);
1257
if (opt->slant != 0.0)
1258
fprintf(stdout, " font-slant=\"%g\"", opt->slant);
1259
if (opt->extend != 1.0)
1260
fprintf(stdout, " font-extend=\"%g\"", opt->extend);
1262
fprintf(stdout, " glyph-order=\"%s\"", opt->charcoll);
1264
fprintf(stdout, " tounicode=\"%s\"", opt->tounicode);
1265
if (opt->index != 0)
1266
fprintf(stdout, " ttc-index=\"%d\"", opt->index);
1267
if (opt->flags & FONTMAP_OPT_NOEMBED)
1268
fprintf(stdout, " embedding=\"no\"");
1269
if (opt->mapc >= 0) {
1270
fprintf(stdout, " charmap=\"pad:");
1271
if (opt->mapc > 0xffff)
1272
fprintf(stdout, "%02x %02x", (opt->mapc >> 16) & 0xff, (opt->mapc >> 8) & 0xff);
1274
fprintf(stdout, "%02x", (opt->mapc >> 8) & 0xff);
1275
fprintf(stdout, "\"");
1277
if (opt->flags & FONTMAP_OPT_VERT)
1278
fprintf(stdout, " writing-mode=\"vertical\"");
1279
if (opt->style != FONTMAP_STYLE_NONE) {
1280
fprintf(stdout, " font-style=\"");
1281
switch (opt->style) {
1282
case FONTMAP_STYLE_BOLD:
1283
fprintf(stdout, "bold");
1285
case FONTMAP_STYLE_ITALIC:
1286
fprintf(stdout, "italic");
1288
case FONTMAP_STYLE_BOLDITALIC:
1289
fprintf(stdout, "bolditalic");
1292
fprintf(stdout, "\"");
1295
fprintf(stdout, " / -->\n");
1297
fprintf(stdout, " />\n");
1301
dump_fontmaps (void)
1303
struct ht_iter iter;
1311
fprintf(stdout, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1312
fprintf(stdout, "<!DOCTYPE fontmap SYSTEM \"fontmap.dtd\">\n");
1313
fprintf(stdout, "<fontmap id=\"%s\">\n", "foo");
1314
if (ht_set_iter(fontmap, &iter) == 0) {
1316
kp = ht_iter_getkey(&iter, &kl);
1317
mrec = ht_iter_getval(&iter);
1320
memcpy(key, kp, kl); key[kl] = 0;
1321
dump_fontmap_rec(key, mrec);
1322
} while (!ht_iter_next(&iter));
1324
ht_clear_iter(&iter);
1325
fprintf(stdout, "</fontmap>\n");
1331
test_fontmap_help (void)
1333
fprintf(stdout, "usage: fontmap [options] [mapfile...]\n");
1334
fprintf(stdout, "-l, --lookup string\n");
1335
fprintf(stdout, " Lookup fontmap entry for 'string' after loading mapfile(s).\n");
1339
test_fontmap_main (int argc, char *argv[])
1346
static struct option long_options[] = {
1347
{"lookup", 1, 0, 'l'},
1348
{"help", 0, 0, 'h'},
1351
c = getopt_long(argc, argv, "l:h", long_options, &optidx);
1360
test_fontmap_help();
1364
test_fontmap_help();
1370
pdf_init_fontmaps();
1371
for (i = optind; i < argc; i++)
1372
pdf_load_fontmap_file(argv[i], FONTMAP_RMODE_REPLACE);
1378
mrec = pdf_lookup_fontmap_record(key);
1380
dump_fontmap_rec(key, mrec);
1382
WARN("Fontmap entry \"%s\" not found.", key);
1385
pdf_close_fontmaps();
1389
#endif /* DPXTEST */