1 /* fontmap.c */
2 
3 /************************************************************************
4 
5   Part of the dvipng distribution
6 
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as
9   published by the Free Software Foundation, either version 3 of the
10   License, or (at your option) any later version.
11 
12   This program is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public
18   License along with this program. If not, see
19   <http://www.gnu.org/licenses/>.
20 
21   Copyright (C) 2002-2015 Jan-�ke Larsson
22 
23 ************************************************************************/
24 
25 #include "dvipng.h"
26 
27 static struct filemmap psfont_mmap;
28 #ifdef HAVE_FT2
29 static struct filemmap ttfont_mmap;
30 #endif
31 static struct psfontmap *psfontmap=NULL;
32 
newword(char ** buffer,char * end)33 static char* newword(char** buffer, char* end)
34 {
35   char *word,*pos=*buffer;
36 
37   while(pos<end && *pos!=' ' && *pos!='\t' && *pos!='"') pos++;
38   if ((word=malloc(pos-*buffer+1))==NULL)
39     Fatal("cannot malloc space for string");
40   strncpy(word,*buffer,pos-*buffer);
41   word[pos-*buffer]='\0';
42   *buffer=pos;
43   return(word);
44 }
45 
copyword(char * orig)46 char* copyword(char* orig)
47 {
48   char *word;
49 
50   if (orig==NULL)
51     return(NULL);
52   if ((word=malloc(strlen(orig)+1))==NULL)
53     Fatal("cannot malloc space for string");
54   strcpy(word,orig);
55   return(word);
56 }
57 
find_format(const char * name)58 static char* find_format(const char* name)
59 {
60   /* Cater for both new (first case) and old (second case) kpathsea */
61   char* format =
62     kpse_find_file(name,kpse_fontmap_format,false);
63 
64   if (format==NULL)
65     format = kpse_find_file(name,kpse_dvips_config_format,false);
66   return(format);
67 }
68 
InitPSFontMap(void)69 void InitPSFontMap(void)
70 {
71   char* psfont_name=NULL;
72   /* Prefer ps2pk.map, fonts are present more often */
73   psfont_name=find_format("ps2pk.map");
74   if (psfont_name==NULL)
75     psfont_name=find_format("psfonts.map");
76   if (psfont_name==NULL) {
77     Warning("cannot find ps2pk.map, nor psfonts.map");
78   } else {
79     DEBUG_PRINT(DEBUG_FT,
80 		("\n  OPEN PSFONT MAP:\t'%s'", psfont_name));
81     if (MmapFile(psfont_name,&psfont_mmap)) {
82       Warning("psfonts map %s could not be opened", psfont_name);
83     }
84     free(psfont_name);
85   }
86 #ifdef HAVE_FT2
87   psfont_name=find_format("ttfonts.map");
88   if (psfont_name!=NULL) {
89     DEBUG_PRINT(DEBUG_FT,("\n  OPEN TTFONT MAP:\t'%s'", psfont_name));
90     if (MmapFile(psfont_name,&ttfont_mmap)) {
91       Warning("ttfonts map %s could not be opened", psfont_name);
92     }
93     free(psfont_name);
94   }
95 #endif
96 }
97 
NewPSFont(struct psfontmap * copyfrom)98 struct psfontmap *NewPSFont(struct psfontmap* copyfrom)
99 {
100   struct psfontmap *newentry=NULL;
101   if ((newentry=malloc(sizeof(struct psfontmap)))==NULL)
102     Fatal("cannot malloc psfontmap space");
103   if (copyfrom!=NULL) {
104     newentry->line = copyfrom->line;
105     newentry->tfmname = copyword(copyfrom->tfmname);
106     newentry->psfile = copyword(copyfrom->psfile);
107     newentry->encname = copyword(copyfrom->encname);
108     newentry->encoding = copyfrom->encoding;
109 #ifdef HAVE_FT2
110     newentry->ft_transformp = copyfrom->ft_transformp;
111     newentry->subfont = copyfrom->subfont;
112 #endif
113     newentry->end = copyfrom->end;
114   } else {
115     newentry->line = NULL;
116     newentry->tfmname = NULL;
117     newentry->psfile = NULL;
118     newentry->encname = NULL;
119     newentry->encoding = NULL;
120 #ifdef HAVE_FT2
121     newentry->ft_transformp = NULL;
122     newentry->subfont = NULL;
123 #endif
124     newentry->end = NULL;
125   }
126   newentry->next=psfontmap;
127   psfontmap=newentry;
128   return(newentry);
129 }
130 
SearchPSFontMap(char * fontname,struct filemmap * search_mmap)131 static struct psfontmap *SearchPSFontMap(char* fontname,
132 					 struct filemmap* search_mmap)
133 {
134   static char *pos=NULL,*end=NULL;
135   static struct filemmap* searching_mmap=NULL;
136   struct psfontmap *entry=NULL;
137 
138   if (pos==end && search_mmap!=searching_mmap) {
139     searching_mmap=search_mmap;
140     pos=searching_mmap->data;
141     end=searching_mmap->data+searching_mmap->size;
142   }
143   while(pos<end && (entry==NULL || strcmp(entry->tfmname,fontname)!=0)) {
144     while(pos < end
145 	  && (*pos=='\r' || *pos=='\n' || *pos==' ' || *pos=='\t'
146 	      || *pos=='%' || *pos=='*' || *pos==';' || *pos=='#')) {
147       while(pos < end && *pos!='\r' && *pos!='\n') pos++; /* skip comments/empty rows */
148       pos++;
149     }
150     if (pos < end) {
151       entry=NewPSFont(NULL);
152       entry->line = pos;
153       /* skip <something and quoted entries */
154       while(pos < end && (*pos=='<' || *pos=='"')) {
155 	if (*pos=='<')
156 	  while(pos < end && *pos!=' ' && *pos!='\t') pos++;
157 	else
158 	  while(pos < end && *pos!='"') pos++;
159 	while(pos < end && (*pos==' ' || *pos=='\t')) pos++;
160       }
161       /* first word is font name */
162       entry->tfmname = newword(&pos,end);
163       while(pos < end && *pos!='\r' && *pos!='\n') pos++;
164       entry->end = pos;
165     }
166     pos++;
167   }
168   if (entry!=NULL && strcmp(entry->tfmname,fontname)!=0)
169     entry=NULL;
170   return(entry);
171 }
172 
ClearPSFontMap(void)173 void ClearPSFontMap(void)
174 {
175   struct psfontmap *entry;
176 
177   while(psfontmap!=NULL) {
178     entry=psfontmap;
179     psfontmap=psfontmap->next;
180     free(entry->tfmname);
181     if (entry->psfile!=NULL)
182       free(entry->psfile);
183     if (entry->encname!=NULL)
184       free(entry->encname);
185     free(entry);
186   }
187   UnMmapFile(&psfont_mmap);
188 #ifdef HAVE_FT2
189   UnMmapFile(&ttfont_mmap);
190 #endif
191 }
192 
ReadPSFontMap(struct psfontmap * entry)193 static void ReadPSFontMap(struct psfontmap *entry)
194 {
195   char *pos,*end,*psname;
196   int nameno = 0;
197 
198   DEBUG_PRINT(DEBUG_FT,("\n  PSFONTMAP: %s ",entry->tfmname));
199   pos=entry->line;
200   end=entry->end;
201   while(pos < end) {
202     if (*pos=='<') {                               /* filename follows */
203       pos++;
204       if (pos<end && *pos=='<') {           /* <<download.font */
205 	pos++;
206 	entry->psfile = newword((char**)&pos,end);
207 	DEBUG_PRINT(DEBUG_FT,("<%s ",entry->psfile));
208       } else if (pos<end && *pos=='[') {    /* <[encoding.file */
209 	pos++;
210 	entry->encname = newword((char**)&pos,end);
211 	DEBUG_PRINT(DEBUG_FT,("<[%s ",entry->encname));
212       } else {                                     /* <some.file      */
213 	char* word =newword((char**)&pos,end);
214 	if (strncmp(word+strlen(word)-4,".enc",4)==0) {/* <some.enc */
215 	  entry->encname=word;
216 	  DEBUG_PRINT(DEBUG_FT,("<[%s ",entry->encname));
217 	} else {                                   /* <font    */
218 	  entry->psfile=word;
219 	  DEBUG_PRINT(DEBUG_FT,("<%s ",entry->psfile));
220 	}
221       }
222     } else if (*pos=='"') { /* PS code: reencoding/tranformation exists */
223       char *word;
224       double cxx=1.0,cxy=0.0;
225       pos++;
226       DEBUG_PRINT(DEBUG_FT,("\""));
227       while(pos < end && *pos!='"') {
228 	word=newword((char**)&pos,end);
229 	while(pos < end && (*pos==' ' || *pos=='\t')) pos++;
230 	if (pos+10<end && strncmp(pos,"ExtendFont",10)==0) {
231 	  cxx=strtod(word,NULL);
232 	  pos+=10;
233 	  DEBUG_PRINT(DEBUG_FT,("%f ExtendFont ",cxx));
234 	} else if (pos+9<end && strncmp(pos,"SlantFont",9)==0) {
235 	  pos+=9;
236 	  cxy=strtod(word,NULL);
237 	  DEBUG_PRINT(DEBUG_FT,("%f SlantFont ",cxy));
238 	} else if (pos+12<end && strncmp(pos,"ReEncodeFont",12)==0) {
239 	    pos+=12;
240 	    DEBUG_PRINT(DEBUG_FT,("%s ReEncodeFont ",word));
241 	} else {
242 	    DEBUG_PRINT(DEBUG_FT,("(?:%s) ",word));
243 	}
244 	free(word);
245       }
246 #ifdef HAVE_FT2
247       entry->ft_transformp=&(entry->ft_transform);
248       entry->ft_transform.xx=(FT_Fixed)(cxx*0x10000);
249       entry->ft_transform.xy=(FT_Fixed)(cxy*0x10000);
250       entry->ft_transform.yx=0;
251       entry->ft_transform.yy=0x10000;
252 #endif
253       DEBUG_PRINT(DEBUG_FT,("\" "));
254       pos++;
255     } else {                                      /* bare word */
256       switch (++nameno) {
257       case 1: /* first word is tfmname and perhaps psname, NOT psfile */
258 	while(pos<end && *pos!=' ' && *pos!='\t') pos++;
259 	psname=entry->tfmname;
260 	break;
261       case 2:                    /* second word is psname, NOT psfile */
262 	psname = newword((char**)&pos,end);
263 	DEBUG_PRINT(DEBUG_FT,("(%s) ",psname));
264 	free(psname);
265 	break;
266       case 3:                             /* third word is encoding */
267 	entry->encname = newword((char**)&pos,end);
268 	DEBUG_PRINT(DEBUG_FT,("<[%s ",entry->encname));
269 	break;
270       default:
271 	while(pos<end && *pos!=' ' && *pos!='\t') pos++;
272 	Warning("more than three bare words in font map entry");
273       }
274     }
275     while(pos < end && (*pos==' ' || *pos=='\t')) pos++;
276   }
277   if (entry->psfile==NULL) {
278     /* No psfile-name given, use tfmname */
279     entry->psfile=copyword(entry->tfmname);
280     DEBUG_PRINT(DEBUG_FT,(" <%s ",entry->psfile));
281   }
282   if (entry->encname!=NULL
283       && (entry->encoding=FindEncoding(entry->encname))==NULL)
284     Warning("unable to load font encoding '%s' for %s",
285 	    entry->encname,entry->tfmname);
286 }
287 
288 
FindPSFontMap(char * fontname)289 struct psfontmap* FindPSFontMap(char* fontname)
290 {
291   struct psfontmap *entry;
292   static struct filemmap* search_mmap_p=&psfont_mmap;
293 
294   entry=psfontmap;
295   while(entry!=NULL && strcmp(entry->tfmname,fontname)!=0)
296     entry=entry->next;
297   if(entry==NULL) {
298     entry=SearchPSFontMap(fontname,search_mmap_p);
299 #ifdef HAVE_FT2
300     if(entry==NULL && search_mmap_p!=&ttfont_mmap) {
301       search_mmap_p=&ttfont_mmap;
302       entry=SearchPSFontMap(fontname,search_mmap_p);
303     }
304   }
305   if(entry==NULL) {
306     struct psfontmap* entry_subfont=NULL;
307     entry=psfontmap;
308     while(entry!=NULL && strcmp(entry->tfmname,fontname)!=0) {
309       while(entry!=NULL && strchr(entry->tfmname,'@')==NULL)
310 	entry=entry->next;
311       if (entry!=NULL) {
312 	entry_subfont=FindSubFont(entry,fontname);
313 	if (entry_subfont!=NULL)
314 	  entry=entry_subfont;
315 	else
316 	  entry=entry->next;
317       }
318     }
319 #endif
320   }
321   if (entry!=NULL && entry->psfile==NULL)
322     ReadPSFontMap(entry);
323   if (entry!=NULL && entry->encname!=NULL && entry->encoding==NULL)
324     /* Encoding given but it cannot be found. Unusable font */
325     return(NULL);
326   return(entry);
327 }
328