1 /*
2 Copyright 2005-2014 Han The Thanh, <thanh@pdftex.org>
3 
4 This file is part of pdfTeX.
5 
6 pdfTeX is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 
11 pdfTeX is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along
17 with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "ptexlib.h"
21 #include <string.h>
22 
23 static struct avl_table *sfd_tree = NULL;
24 
25 #define SFD_BUF_SIZE    SMALL_BUF_SIZE
26 #define sfd_getchar()   getc(sfd_file)
27 #define sfd_eof()       feof(sfd_file)
28 #define sfd_close()     xfclose(sfd_file, cur_file_name)
29 #define sfd_open()      open_input(&sfd_file, kpse_sfd_format, FOPEN_RBIN_MODE)
30 static FILE *sfd_file;
31 static char sfd_line[SFD_BUF_SIZE];
32 
new_subfont_entry(void)33 static subfont_entry *new_subfont_entry(void)
34 {
35     int i;
36     subfont_entry *subfont;
37     subfont = xtalloc(1, subfont_entry);
38     subfont->infix = NULL;
39     for (i = 0; i < 256; i++)
40         subfont->charcodes[i] = -1;     /* unassigned */
41     subfont->next = NULL;
42     return subfont;
43 }
44 
new_sfd_entry(void)45 static sfd_entry *new_sfd_entry(void)
46 {
47     sfd_entry *sfd;
48     sfd = xtalloc(1, sfd_entry);
49     sfd->name = NULL;
50     sfd->subfont = NULL;
51     return sfd;
52 }
53 
destroy_sfd_entry(void * pa,void * pb)54 static void destroy_sfd_entry(void *pa, void *pb)
55 {
56     subfont_entry *p, *q;
57     sfd_entry *sfd;
58     sfd = (sfd_entry *) pa;
59     p = sfd->subfont;
60     while (p != NULL) {
61         q = p->next;
62         xfree(p->infix);
63         xfree(p);
64         p = q;
65     }
66     xfree(sfd->name);
67 }
68 
comp_sfd_entry(const void * pa,const void * pb,void * p)69 static int comp_sfd_entry(const void *pa, const void *pb, void *p)
70 {
71     return strcmp(((const sfd_entry *) pa)->name,
72                   ((const sfd_entry *) pb)->name);
73 }
74 
sfd_free(void)75 void sfd_free(void)
76 {
77     if (sfd_tree != NULL)
78         avl_destroy(sfd_tree, destroy_sfd_entry);
79 }
80 
sfd_getline(boolean expect_eof)81 static void sfd_getline(boolean expect_eof)
82 {
83     char *p;
84     int c;
85   restart:
86     if (sfd_eof()) {
87         if (expect_eof)
88             return;
89         else
90             pdftex_fail("unexpected end of file");
91     }
92     p = sfd_line;
93     do {
94         c = sfd_getchar();
95         append_char_to_buf(c, p, sfd_line, SFD_BUF_SIZE);
96     } while (c != 10);
97     append_eol(p, sfd_line, SFD_BUF_SIZE);
98     if (p - sfd_line < 2 || *sfd_line == '#')
99         goto restart;
100 }
101 
read_sfd(char * sfd_name)102 static sfd_entry *read_sfd(char *sfd_name)
103 {
104     void **aa;
105     sfd_entry *sfd, tmp_sfd;
106     subfont_entry *sf;
107     char buf[SMALL_BUF_SIZE], *p;
108     long int i, j, k;
109     int n;
110     /* check whether this sfd has been read */
111     tmp_sfd.name = sfd_name;
112     if (sfd_tree == NULL) {
113         sfd_tree = avl_create(comp_sfd_entry, NULL, &avl_xallocator);
114         assert(sfd_tree != NULL);
115     }
116     sfd = (sfd_entry *) avl_find(sfd_tree, &tmp_sfd);
117     if (sfd != NULL)
118         return sfd;
119     set_cur_file_name(sfd_name);
120     if (!sfd_open()) {
121         pdftex_warn("cannot open SFD file for reading");
122         cur_file_name = NULL;
123         return NULL;
124     }
125     tex_printf("{");
126     tex_printf("%s", cur_file_name);
127     sfd = new_sfd_entry();
128     sfd->name = xstrdup(sfd_name);
129     while (!sfd_eof()) {
130         sfd_getline(true);
131         if (*sfd_line == 10)    /* empty line indicating eof */
132             break;
133         sf = new_subfont_entry();
134         sf->next = sfd->subfont;
135         sfd->subfont = sf;
136         sscanf(sfd_line, "%s %n", buf, &n);
137         sf->infix = xstrdup(buf);
138         p = sfd_line + n;       /* skip to the next word */
139         k = 0;
140       read_ranges:
141         for (;;) {
142             if (*p == '\\') {   /* continue on next line */
143                 sfd_getline(false);
144                 p = sfd_line;
145                 goto read_ranges;
146             } else if (*p == 0) /* end of subfont */
147                 break;
148             if (sscanf(p, " %li %n", &i, &n) == 0)
149                 pdftex_fail("invalid token:\n%s", p);
150             p += n;
151             if (*p == ':') {    /* offset */
152                 k = i;
153                 p++;
154             } else if (*p == '_') {     /* range */
155                 if (sscanf(p + 1, " %li %n", &j, &n) == 0)
156                     pdftex_fail("invalid token:\n%s", p);
157                 if (i > j || k + (j - i) > 255)
158                     pdftex_fail("invalid range:\n%s", p);
159                 while (i <= j)
160                     sf->charcodes[k++] = i++;
161                 p += n + 1;
162             } else              /* codepoint */
163                 sf->charcodes[k++] = i;
164         }
165     }
166     sfd_close();
167     tex_printf("}");
168     aa = avl_probe(sfd_tree, sfd);
169     assert(aa != NULL);
170     return sfd;
171 }
172 
handle_subfont_fm(fm_entry * fm,int mode)173 boolean handle_subfont_fm(fm_entry * fm, int mode)
174 {
175     size_t l;
176     char *p, *q, *r;
177     sfd_entry *sfd;
178     subfont_entry *sf;
179     fm_entry *fm2;
180     char buf[SMALL_BUF_SIZE];
181     assert(fm->tfm_name != NULL);
182 
183     p = fm->tfm_name;
184     q = strchr(p, '@');         /* search for the first '@' */
185     if (q == NULL)
186         return false;
187     r = strchr(q + 1, '@');     /* search for the second '@' */
188     if (r == NULL)
189         return false;
190     if (q <= p || r <= q + 1    /* prefix or sfd name is empty */
191         || r - p != strlen(p) - 1)      /* or the second '@' is not the last char yet */
192         return false;
193     l = r - (q + 1);            /* length of sfd name */
194     strncpy(buf, q + 1, l);
195     buf[l] = 0;
196     check_buf(strlen(buf) + 4, SMALL_BUF_SIZE);
197     strcat(buf, ".sfd");
198     sfd = read_sfd(buf);
199     if (sfd == NULL)
200         return false;
201 
202     /* at this point we know fm is a subfont */
203     set_subfont(fm);
204     xfree(fm->ps_name);
205     fm->ps_name = NULL;
206     /* set default values for PidEid */
207     if (fm->pid == -1) {
208         fm->pid = 3;
209         fm->eid = 1;
210     }
211     l = q - p;                  /* length of base tfm name (prefix) */
212     for (sf = sfd->subfont; sf != NULL; sf = sf->next) {
213         strncpy(buf, p, l);
214         buf[l] = 0;
215         strcat(buf, sf->infix);
216         fm2 = new_fm_entry();
217         fm2->tfm_name = xstrdup(buf);
218         fm2->ff_name = xstrdup(fm->ff_name);
219         fm2->type = fm->type;
220         fm2->pid = fm->pid;
221         fm2->eid = fm->eid;
222         fm2->subfont = sf;
223         if (avl_do_entry(fm2, mode) != 0)       /* try to insert the entry */
224             delete_fm_entry(fm2);       /* delete it if failed */
225     }
226     delete_fm_entry(fm);
227     return true;
228 }
229