w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

sfd.c
Go to the documentation of this file.
1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "fontforge.h"
28 #include <utype.h>
29 #include <sys/stat.h>
30 
31 #ifndef NAME_MAX
32 # ifndef _POSIX_NAME_MAX
33 # define _POSIX_NAME_MAX 512
34 # endif
35 # define NAME_MAX _POSIX_NAME_MAX
36 #endif
37 
38 static const char *joins[] = { "miter", "round", "bevel", "inher", NULL };
39 static const char *caps[] = { "butt", "round", "square", "inher", NULL };
40 static const char *spreads[] = { "pad", "reflect", "repeat", NULL };
41 
42 #define SFD_PTFLAG_TYPE_MASK 0x3
43 #define SFD_PTFLAG_IS_SELECTED 0x4
44 #define SFD_PTFLAG_NEXTCP_IS_DEFAULT 0x8
45 #define SFD_PTFLAG_PREVCP_IS_DEFAULT 0x10
46 #define SFD_PTFLAG_ROUND_IN_X 0x20
47 #define SFD_PTFLAG_ROUND_IN_Y 0x40
48 #define SFD_PTFLAG_INTERPOLATE 0x80
49 #define SFD_PTFLAG_INTERPOLATE_NEVER 0x100
50 #define SFD_PTFLAG_PREV_EXTREMA_MARKED_ACCEPTABLE 0x200
51 #define SFD_PTFLAG_FORCE_OPEN_PATH 0x400
52 
53 
54 
55 
56 /* I will retain this list in case there are still some really old sfd files */
57 /* including numeric encodings. This table maps them to string encodings */
58 static const char *charset_names[] = {
59  "custom",
60  "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
61  "iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10",
62  "iso8859-11", "iso8859-13", "iso8859-14", "iso8859-15",
63  "koi8-r",
64  "jis201",
65  "win", "mac", "symbol", "zapfding", "adobestandard",
66  "jis208", "jis212", "ksc5601", "gb2312", "big5", "big5hkscs", "johab",
67  "unicode", "unicode4", "sjis", "wansung", "gb2312pk", NULL};
68 
69 static const char *unicode_interp_names[] = { "none", "adobe", "greek",
70  "japanese", "tradchinese", "simpchinese", "korean", "ams", NULL };
71 
72 /* sfdir files and extensions */
73 #define FONT_PROPS "font.props"
74 #define STRIKE_PROPS "strike.props"
75 #define EXT_CHAR '.'
76 #define GLYPH_EXT ".glyph"
77 #define BITMAP_EXT ".bitmap"
78 #define STRIKE_EXT ".strike"
79 #define SUBFONT_EXT ".subfont"
80 #define INSTANCE_EXT ".instance"
81 
82 signed char inbase64[256] = {
83  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
84  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
85  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
86  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
87  -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
88  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
89  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
90  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
91  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
92  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
93  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
94  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
95  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
96  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
97  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
98  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
99 };
100 
101 static const char *end_tt_instrs = "EndTTInstrs";
102 static RefChar *SFDGetRef(FILE *sfd, int was_enc);
104 static StemInfo *SFDReadHints(FILE *sfd);
105 static DStemInfo *SFDReadDHints( SplineFont *sf,FILE *sfd,int old );
106 extern uint8 *_IVParse(SplineFont *sf, char *text, int *len, void (*IVError)(void *,char *, int), void *iv);
107 
108 static int PeekMatch(FILE *stream, const char * target) {
109  // This returns 1 if target matches the next characters in the stream.
110  int pos1 = 0;
111  int lastread = getc(stream);
112  while (target[pos1] != '\0' && lastread != EOF && lastread == target[pos1]) {
113  pos1 ++; lastread = getc(stream);
114  }
115 
116  int rewind_amount = pos1 + ((lastread == EOF) ? 0 : 1);
117  fseek(stream, -rewind_amount, SEEK_CUR);
118  return (target[pos1] == '\0');
119 }
120 
121 /* Long lines can be broken by inserting \\\n (backslash newline) */
122 /* into the line. I don't think this is ever ambiguous as I don't */
123 /* think a line can end with backslash */
124 /* UPDATE: it can... that's handled in getquotedeol() below. */
125 static int nlgetc(FILE *sfd) {
126  int ch, ch2;
127 
128  ch=getc(sfd);
129  if ( ch!='\\' )
130 return( ch );
131  ch2 = getc(sfd);
132  if ( ch2=='\n' )
133 return( nlgetc(sfd));
134  ungetc(ch2,sfd);
135 return( ch );
136 }
137 
138 static char *SFDReadUTF7Str(FILE *sfd) {
139  char *buffer = NULL, *pt, *end = NULL;
140  int ch1, ch2, ch3, ch4, done, c;
141  int prev_cnt=0, prev=0, in=0;
142 
143  ch1 = nlgetc(sfd);
144  while ( isspace(ch1) && ch1!='\n' && ch1!='\r') ch1 = nlgetc(sfd);
145  if ( ch1=='\n' || ch1=='\r' )
146  ungetc(ch1,sfd);
147  if ( ch1!='"' )
148 return( NULL );
149  pt = 0;
150  while ( (ch1=nlgetc(sfd))!=EOF && ch1!='"' ) {
151  done = 0;
152  if ( !done && !in ) {
153  if ( ch1=='+' ) {
154  ch1 = nlgetc(sfd);
155  if ( ch1=='-' ) {
156  ch1 = '+';
157  done = true;
158  } else {
159  in = true;
160  prev_cnt = 0;
161  }
162  } else
163  done = true;
164  }
165  if ( !done ) {
166  if ( ch1=='-' ) {
167  in = false;
168  } else if ( inbase64[ch1]==-1 ) {
169  in = false;
170  done = true;
171  } else {
172  ch1 = inbase64[ch1];
173  ch2 = inbase64[c = nlgetc(sfd)];
174  if ( ch2==-1 ) {
175  ungetc(c, sfd);
176  ch2 = ch3 = ch4 = 0;
177  } else {
178  ch3 = inbase64[c = nlgetc(sfd)];
179  if ( ch3==-1 ) {
180  ungetc(c, sfd);
181  ch3 = ch4 = 0;
182  } else {
183  ch4 = inbase64[c = nlgetc(sfd)];
184  if ( ch4==-1 ) {
185  ungetc(c, sfd);
186  ch4 = 0;
187  }
188  }
189  }
190  ch1 = (ch1<<18) | (ch2<<12) | (ch3<<6) | ch4;
191  if ( prev_cnt==0 ) {
192  prev = ch1&0xff;
193  ch1 >>= 8;
194  prev_cnt = 1;
195  } else /* if ( prev_cnt == 1 ) */ {
196  ch1 |= (prev<<24);
197  prev = (ch1&0xffff);
198  ch1 = (ch1>>16)&0xffff;
199  prev_cnt = 2;
200  }
201  done = true;
202  }
203  }
204  if ( pt+10>=end ) {
205  if ( buffer==NULL ) {
206  pt = buffer = malloc(400);
207  end = buffer+400;
208  } else if (pt) {
209  char *temp = realloc(buffer,end-buffer+400);
210  pt = temp+(pt-buffer);
211  end = temp+(end-buffer+400);
212  buffer = temp;
213  }
214  }
215  if ( pt && done )
216  pt = utf8_idpb(pt,ch1,0);
217  if ( prev_cnt==2 ) {
218  prev_cnt = 0;
219  if ( pt && prev!=0 )
220  pt = utf8_idpb(pt,prev,0);
221  }
222  if ( pt==0 ) {
223  free(buffer);
224  return( NULL );
225  }
226  }
227  if ( buffer==NULL )
228 return( NULL );
229  *pt = '\0';
230  pt = copy(buffer);
231  free(buffer );
232 return( pt );
233 }
234 
235 struct enc85 {
237  unsigned char sofar[4];
238  int pos;
239  int ccnt;
240 };
241 
242 static void *SFDUnPickle(FILE *sfd, int python_data_has_lists) {
243  int ch, quoted;
244  static int max = 0;
245  static char *buf = NULL;
246  char *pt, *end;
247  int cnt;
248 
249  pt = buf; end = buf+max;
250  while ( (ch=nlgetc(sfd))!='"' && ch!='\n' && ch!=EOF );
251  if ( ch!='"' )
252 return( NULL );
253 
254  quoted = false;
255  while ( ((ch=nlgetc(sfd))!='"' || quoted) && ch!=EOF ) {
256  if ( !quoted && ch=='\\' )
257  quoted = true;
258  else {
259  if ( pt>=end ) {
260  cnt = pt-buf;
261  buf = realloc(buf,(max+=200)+1);
262  pt = buf+cnt;
263  end = buf+max;
264  }
265  *pt++ = ch;
266  quoted = false;
267  }
268  }
269  if ( pt==buf )
270 return( NULL );
271  *pt='\0';
272 #ifdef _NO_PYTHON
273 return( copy(buf));
274 #else
275 return( PyFF_UnPickleMeToObjects(buf));
276 #endif
277  /* buf is a static buffer, I don't free it, I'll reuse it next time */
278 }
279 
280 /* ********************************* INPUT ********************************** */
281 #include "sfd1.h"
282 
283 char *getquotedeol(FILE *sfd) {
284  char *pt, *str, *end;
285  int ch;
286 
287  pt = str = malloc(101); end = str+100;
288  while ( isspace(ch = nlgetc(sfd)) && ch!='\r' && ch!='\n' );
289  while ( ch!='\n' && ch!='\r' && ch!=EOF ) {
290  if ( ch=='\\' ) {
291  /* We can't use nlgetc() here, because it would misinterpret */
292  /* double backslash at the end of line. Multiline strings, */
293  /* broken with backslash + newline, are just handled above. */
294  ch = getc(sfd);
295  if ( ch=='n' ) ch='\n';
296  /* else if ( ch=='\\' ) ch=='\\'; */ /* second backslash of '\\' */
297 
298  /* FontForge doesn't write other escape sequences in this context. */
299  /* So any other value of ch is assumed impossible. */
300  }
301  if ( pt>=end ) {
302  pt = realloc(str,end-str+101);
303  end = pt+(end-str)+100;
304  str = pt;
305  pt = end-100;
306  }
307  *pt++ = ch;
308  ch = nlgetc(sfd);
309  }
310  *pt='\0';
311  /* these strings should be in utf8 now, but some old sfd files might have */
312  /* latin1. Not a severe problems because they SHOULD be in ASCII. So any */
313  /* non-ascii strings are erroneous anyway */
314  if ( !utf8_valid(str) ) {
316  free(str);
317  str = pt;
318  }
319 return( str );
320 }
321 
322 static int geteol(FILE *sfd, char *tokbuf) {
323  char *pt=tokbuf, *end = tokbuf+2000-2; int ch;
324 
325  while ( isspace(ch = nlgetc(sfd)) && ch!='\r' && ch!='\n' );
326  while ( ch!='\n' && ch!='\r' && ch!=EOF ) {
327  if ( pt<end ) *pt++ = ch;
328  ch = nlgetc(sfd);
329  }
330  *pt='\0';
331 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
332 }
333 
334 static int getprotectedname(FILE *sfd, char *tokbuf) {
335  char *pt=tokbuf, *end = tokbuf+100-2; int ch;
336 
337  while ( (ch = nlgetc(sfd))==' ' || ch=='\t' );
338  while ( ch!=EOF && !isspace(ch) && ch!='[' && ch!=']' && ch!='{' && ch!='}' && ch!='<' && ch!='%' ) {
339  if ( pt<end ) *pt++ = ch;
340  ch = nlgetc(sfd);
341  }
342  if ( pt==tokbuf && ch!=EOF )
343  *pt++ = ch;
344  else
345  ungetc(ch,sfd);
346  *pt='\0';
347 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
348 }
349 
350 int getname(FILE *sfd, char *tokbuf) {
351  int ch;
352 
353  while ( isspace(ch = nlgetc(sfd)));
354  ungetc(ch,sfd);
355 return( getprotectedname(sfd,tokbuf));
356 }
357 
358 static uint32 gettag(FILE *sfd) {
359  int ch, quoted;
360  uint32 tag;
361 
362  while ( (ch=nlgetc(sfd))==' ' );
363  if ( (quoted = (ch=='\'')) ) ch = nlgetc(sfd);
364  tag = (ch<<24)|(nlgetc(sfd)<<16);
365  tag |= nlgetc(sfd)<<8;
366  tag |= nlgetc(sfd);
367  if ( quoted ) (void) nlgetc(sfd);
368 return( tag );
369 }
370 
371 static int getint(FILE *sfd, int *val) {
372  char tokbuf[100]; int ch;
373  char *pt=tokbuf, *end = tokbuf+100-2;
374 
375  while ( isspace(ch = nlgetc(sfd)));
376  if ( ch=='-' || ch=='+' ) {
377  *pt++ = ch;
378  ch = nlgetc(sfd);
379  }
380  while ( isdigit(ch)) {
381  if ( pt<end ) *pt++ = ch;
382  ch = nlgetc(sfd);
383  }
384  *pt='\0';
385  ungetc(ch,sfd);
386  *val = strtol(tokbuf,NULL,10);
387 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
388 }
389 
390 static int getlonglong(FILE *sfd, long long *val) {
391  char tokbuf[100]; int ch;
392  char *pt=tokbuf, *end = tokbuf+100-2;
393 
394  while ( isspace(ch = nlgetc(sfd)));
395  if ( ch=='-' || ch=='+' ) {
396  *pt++ = ch;
397  ch = nlgetc(sfd);
398  }
399  while ( isdigit(ch)) {
400  if ( pt<end ) *pt++ = ch;
401  ch = nlgetc(sfd);
402  }
403  *pt='\0';
404  ungetc(ch,sfd);
405  *val = strtoll(tokbuf,NULL,10);
406 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
407 }
408 
409 static int gethex(FILE *sfd, uint32 *val) {
410  char tokbuf[100]; int ch;
411  char *pt=tokbuf, *end = tokbuf+100-2;
412 
413  while ( isspace(ch = nlgetc(sfd)));
414  if ( ch=='#' )
415  ch = nlgetc(sfd);
416  if ( ch=='-' || ch=='+' ) {
417  *pt++ = ch;
418  ch = nlgetc(sfd);
419  }
420  if ( ch=='0' ) {
421  ch = nlgetc(sfd);
422  if ( ch=='x' || ch=='X' )
423  ch = nlgetc(sfd);
424  else {
425  ungetc(ch,sfd);
426  ch = '0';
427  }
428  }
429  while ( isdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F')) {
430  if ( pt<end ) *pt++ = ch;
431  ch = nlgetc(sfd);
432  }
433  *pt='\0';
434  ungetc(ch,sfd);
435  *val = strtoul(tokbuf,NULL,16);
436 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
437 }
438 
439 static int gethexints(FILE *sfd, uint32 *val, int cnt) {
440  int i, ch;
441 
442  for ( i=0; i<cnt; ++i ) {
443  if ( i!=0 ) {
444  ch = nlgetc(sfd);
445  if ( ch!='.' ) ungetc(ch,sfd);
446  }
447  if ( !gethex(sfd,&val[i]))
448 return( false );
449  }
450 return( true );
451 }
452 
453 static int getsint(FILE *sfd, int16 *val) {
454  int val2;
455  int ret = getint(sfd,&val2);
456  *val = val2;
457 return( ret );
458 }
459 
460 static int getusint(FILE *sfd, uint16 *val) {
461  int val2;
462  int ret = getint(sfd,&val2);
463  *val = val2;
464 return( ret );
465 }
466 
467 static int getreal(FILE *sfd, real *val) {
468  char tokbuf[100];
469  int ch;
470  char *pt=tokbuf, *end = tokbuf+100-2, *nend;
471 
472  while ( isspace(ch = nlgetc(sfd)));
473  if ( ch!='e' && ch!='E' ) /* real's can't begin with exponants */
474  while ( isdigit(ch) || ch=='-' || ch=='+' || ch=='e' || ch=='E' || ch=='.' || ch==',' ) {
475  if ( pt<end ) *pt++ = ch;
476  ch = nlgetc(sfd);
477  }
478  *pt='\0';
479  ungetc(ch,sfd);
480  *val = strtod(tokbuf,&nend);
481  /* Beware of different locals! */
482  if ( *nend!='\0' ) {
483  if ( *nend=='.' )
484  *nend = ',';
485  else if ( *nend==',' )
486  *nend = '.';
487  *val = strtod(tokbuf,&nend);
488  }
489 return( pt!=tokbuf && *nend=='\0'?1:ch==EOF?-1: 0 );
490 }
491 
492 /* Don't use nlgetc here. We carefully control newlines when dumping in 85 */
493 /* but backslashes can occur at end of line. */
494 static int Dec85(struct enc85 *dec) {
495  int ch1, ch2, ch3, ch4, ch5;
496  unsigned int val;
497 
498  if ( dec->pos<0 ) {
499  while ( isspace(ch1=getc(dec->sfd)));
500  if ( ch1=='z' ) {
501  dec->sofar[0] = dec->sofar[1] = dec->sofar[2] = dec->sofar[3] = 0;
502  dec->pos = 3;
503  } else {
504  while ( isspace(ch2=getc(dec->sfd)));
505  while ( isspace(ch3=getc(dec->sfd)));
506  while ( isspace(ch4=getc(dec->sfd)));
507  while ( isspace(ch5=getc(dec->sfd)));
508  val = ((((ch1-'!')*85+ ch2-'!')*85 + ch3-'!')*85 + ch4-'!')*85 + ch5-'!';
509  dec->sofar[3] = val>>24;
510  dec->sofar[2] = val>>16;
511  dec->sofar[1] = val>>8;
512  dec->sofar[0] = val;
513  dec->pos = 3;
514  }
515  }
516 return( dec->sofar[dec->pos--] );
517 }
518 
519 static void SFDGetType1(FILE *sfd) {
520  /* We've read the OrigType1 token (this is now obselete, but parse it in case there are any old sfds) */
521  int len;
522  struct enc85 dec;
523 
524  memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
525  dec.sfd = sfd;
526 
527  getint(sfd,&len);
528  while ( --len >= 0 )
529  Dec85(&dec);
530 }
531 
533  /* We've read the TtfInstr token, it is followed by a byte count */
534  /* and then the instructions in enc85 format */
535  int i,len;
536  struct enc85 dec;
537 
538  memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
539  dec.sfd = sfd;
540 
541  getint(sfd,&len);
542  sc->ttf_instrs = malloc(len);
543  sc->ttf_instrs_len = len;
544  for ( i=0; i<len; ++i )
545  sc->ttf_instrs[i] = Dec85(&dec);
546 }
547 
548 static void tterr(void *UNUSED(rubbish), char *message, int UNUSED(pos)) {
549  LogError(_("When loading tt instrs from sfd: %s\n"), message );
550 }
551 
553  /* We've read the TtInstr token, it is followed by text versions of */
554  /* the instructions, slurp it all into a big buffer, and then parse that */
555  char *buf=NULL, *pt=buf, *end=buf;
556  int ch;
557  int backlen = strlen(end_tt_instrs);
558  int instr_len;
559 
560  while ( (ch=nlgetc(sfd))!=EOF ) {
561  if ( pt>=end ) {
562  char *newbuf = realloc(buf,(end-buf+200));
563  pt = newbuf+(pt-buf);
564  end = newbuf+(end+200-buf);
565  buf = newbuf;
566  }
567  *pt++ = ch;
568  if ( pt-buf>backlen && strncmp(pt-backlen,end_tt_instrs,backlen)==0 ) {
569  pt -= backlen;
570  break;
571  }
572  }
573  *pt = '\0';
574 
575  sc->ttf_instrs = _IVParse(sc->parent,buf,&instr_len,tterr,NULL);
576  sc->ttf_instrs_len = instr_len;
577 
578  free(buf);
579 }
580 
581 static struct ttf_table *SFDGetTtfTable(FILE *sfd, SplineFont *sf,struct ttf_table *lasttab[2]) {
582  /* We've read the TtfTable token, it is followed by a tag and a byte count */
583  /* and then the instructions in enc85 format */
584  int i,len;
585  int which;
586  struct enc85 dec;
587  struct ttf_table *tab = chunkalloc(sizeof(struct ttf_table));
588 
589  memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
590  dec.sfd = sfd;
591 
592  tab->tag = gettag(sfd);
593 
594  if ( tab->tag==CHR('f','p','g','m') || tab->tag==CHR('p','r','e','p') ||
595  tab->tag==CHR('c','v','t',' ') || tab->tag==CHR('m','a','x','p'))
596  which = 0;
597  else
598  which = 1;
599 
600  getint(sfd,&len);
601  tab->data = malloc(len);
602  tab->len = len;
603  for ( i=0; i<len; ++i )
604  tab->data[i] = Dec85(&dec);
605 
606  if ( lasttab[which]!=NULL )
607  lasttab[which]->next = tab;
608  else if ( which==0 )
609  sf->ttf_tables = tab;
610  else
611  sf->ttf_tab_saved = tab;
612  lasttab[which] = tab;
613 return( tab );
614 }
615 
616 static struct ttf_table *SFDGetShortTable(FILE *sfd, SplineFont *sf,struct ttf_table *lasttab[2]) {
617  /* We've read the ShortTable token, it is followed by a tag and a word count */
618  /* and then the (text) values of the words that make up the cvt table */
619  int i,len, ch;
620  uint8 *pt;
621  int which, iscvt, started;
622  struct ttf_table *tab = chunkalloc(sizeof(struct ttf_table));
623 
624  tab->tag = gettag(sfd);
625 
626  if ( tab->tag==CHR('f','p','g','m') || tab->tag==CHR('p','r','e','p') ||
627  tab->tag==CHR('c','v','t',' ') || tab->tag==CHR('m','a','x','p'))
628  which = 0;
629  else
630  which = 1;
631  iscvt = tab->tag==CHR('c','v','t',' ');
632 
633  getint(sfd,&len);
634  pt = tab->data = malloc(2*len);
635  tab->len = 2*len;
636  started = false;
637  for ( i=0; i<len; ++i ) {
638  int num;
639  getint(sfd,&num);
640  *pt++ = num>>8;
641  *pt++ = num&0xff;
642  if ( iscvt ) {
643  ch = nlgetc(sfd);
644  if ( ch==' ' ) {
645  if ( !started ) {
646  sf->cvt_names = calloc(len+1,sizeof(char *));
647  sf->cvt_names[len] = END_CVT_NAMES;
648  started = true;
649  }
650  sf->cvt_names[i] = SFDReadUTF7Str(sfd);
651  } else
652  ungetc(ch,sfd);
653  }
654  }
655 
656  if ( lasttab[which]!=NULL )
657  lasttab[which]->next = tab;
658  else if ( which==0 )
659  sf->ttf_tables = tab;
660  else
661  sf->ttf_tab_saved = tab;
662  lasttab[which] = tab;
663 return( tab );
664 }
665 
666 static struct ttf_table *SFDGetTtTable(FILE *sfd, SplineFont *sf,struct ttf_table *lasttab[2]) {
667  /* We've read the TtTable token, it is followed by a tag */
668  /* and then the instructions in text format */
669  int ch;
670  int which;
671  struct ttf_table *tab = chunkalloc(sizeof(struct ttf_table));
672  char *buf=NULL, *pt=buf, *end=buf;
673  int backlen = strlen(end_tt_instrs);
674 
675  tab->tag = gettag(sfd);
676 
677  if ( tab->tag==CHR('f','p','g','m') || tab->tag==CHR('p','r','e','p') ||
678  tab->tag==CHR('c','v','t',' ') || tab->tag==CHR('m','a','x','p'))
679  which = 0;
680  else
681  which = 1;
682 
683  while ( (ch=nlgetc(sfd))!=EOF ) {
684  if ( pt>=end ) {
685  char *newbuf = realloc(buf,(end-buf+200));
686  pt = newbuf+(pt-buf);
687  end = newbuf+(end+200-buf);
688  buf = newbuf;
689  }
690  *pt++ = ch;
691  if ( pt-buf>backlen && strncmp(pt-backlen,end_tt_instrs,backlen)==0 ) {
692  pt -= backlen;
693  break;
694  }
695  }
696  *pt = '\0';
697  tab->data = _IVParse(sf,buf,(int*)&tab->len,tterr,NULL);
698  free(buf);
699 
700  if ( lasttab[which]!=NULL )
701  lasttab[which]->next = tab;
702  else if ( which==0 )
703  sf->ttf_tables = tab;
704  else
705  sf->ttf_tab_saved = tab;
706  lasttab[which] = tab;
707 return( tab );
708 }
709 
710 static int SFDCloseCheck(SplinePointList *spl,int order2) {
711  if ( spl->first!=spl->last &&
712  RealNear(spl->first->me.x,spl->last->me.x) &&
713  RealNear(spl->first->me.y,spl->last->me.y)) {
714  SplinePoint *oldlast = spl->last;
715  spl->first->prevcp = oldlast->prevcp;
716  spl->first->noprevcp = oldlast->noprevcp;
717  oldlast->prev->from->next = NULL;
718  spl->last = oldlast->prev->from;
719  chunkfree(oldlast->prev,sizeof(*oldlast));
720  chunkfree(oldlast->hintmask,sizeof(HintMask));
721  chunkfree(oldlast,sizeof(*oldlast));
722  SplineMake(spl->last,spl->first,order2);
723  spl->last = spl->first;
724 return( true );
725  }
726 return( false );
727 }
728 
729 static void SFDGetHintMask(FILE *sfd,HintMask *hintmask) {
730  int nibble = 0, ch;
731 
732  memset(hintmask,0,sizeof(HintMask));
733  for (;;) {
734  ch = nlgetc(sfd);
735  if ( isdigit(ch))
736  ch -= '0';
737  else if ( ch>='a' && ch<='f' )
738  ch -= 'a'-10;
739  else if ( ch>='A' && ch<='F' )
740  ch -= 'A'-10;
741  else {
742  ungetc(ch,sfd);
743  break;
744  }
745  if ( nibble<2*HntMax/8 )
746  (*hintmask)[nibble>>1] |= ch<<(4*(1-(nibble&1)));
747  ++nibble;
748  }
749 }
750 
751 static void SFDGetSpiros(FILE *sfd,SplineSet *cur) {
752  int ch;
753  spiro_cp cp;
754 
755  ch = nlgetc(sfd); /* S */
756  ch = nlgetc(sfd); /* p */
757  ch = nlgetc(sfd); /* i */
758  ch = nlgetc(sfd); /* r */
759  ch = nlgetc(sfd); /* o */
760  while ( fscanf(sfd,"%lg %lg %c", &cp.x, &cp.y, &cp.ty )==3 ) {
761  if ( cur!=NULL ) {
762  if ( cur->spiro_cnt>=cur->spiro_max )
763  cur->spiros = realloc(cur->spiros,(cur->spiro_max+=10)*sizeof(spiro_cp));
764  cur->spiros[cur->spiro_cnt++] = cp;
765  }
766  }
767  if ( cur!=NULL && (cur->spiros[cur->spiro_cnt-1].ty&0x7f)!=SPIRO_END ) {
768  if ( cur->spiro_cnt>=cur->spiro_max )
769  cur->spiros = realloc(cur->spiros,(cur->spiro_max+=1)*sizeof(spiro_cp));
770  memset(&cur->spiros[cur->spiro_cnt],0,sizeof(spiro_cp));
771  cur->spiros[cur->spiro_cnt++].ty = SPIRO_END;
772  }
773  ch = nlgetc(sfd);
774  if ( ch=='E' ) {
775  ch = nlgetc(sfd); /* n */
776  ch = nlgetc(sfd); /* d */
777  ch = nlgetc(sfd); /* S */
778  ch = nlgetc(sfd); /* p */
779  ch = nlgetc(sfd); /* i */
780  ch = nlgetc(sfd); /* r */
781  ch = nlgetc(sfd); /* o */
782  } else
783  ungetc(ch,sfd);
784 }
785 
786 static SplineSet *SFDGetSplineSet(FILE *sfd,int order2) {
789  real stack[100];
790  int sp=0;
791  SplinePoint *pt = NULL;
792  int ch;
793  int ch2;
794  char tok[100];
795  int ttfindex = 0;
796  int lastacceptable;
797 
798  current.x = current.y = 0;
799  lastacceptable = 0;
800  while ( 1 ) {
801  int have_read_val = 0;
802  int val = 0;
803 
804  while ( getreal(sfd,&stack[sp])==1 )
805  if ( sp<99 )
806  ++sp;
807  while ( isspace(ch=nlgetc(sfd)));
808  if ( ch=='E' || ch=='e' || ch==EOF )
809  break;
810  if ( ch=='S' ) {
811  ungetc(ch,sfd);
812  SFDGetSpiros(sfd,cur);
813  continue;
814  } else if (( ch=='N' ) &&
815  nlgetc(sfd)=='a' && /* a */
816  nlgetc(sfd)=='m' && /* m */
817  nlgetc(sfd)=='e' && /* e */
818  nlgetc(sfd)=='d' ) /* d */ {
819  ch2 = nlgetc(sfd); /* : */
820  // We are either fetching a splineset name (Named:) or a point name (NamedP:).
821  if (ch2=='P') { if ((nlgetc(sfd)==':') && (pt!=NULL)) { if (pt->name!=NULL) {free(pt->name);} pt->name = SFDReadUTF7Str(sfd); } }
822  else if (ch2==':') { if (cur != NULL) cur->contour_name = SFDReadUTF7Str(sfd); else { char * freetmp = SFDReadUTF7Str(sfd); free(freetmp); freetmp = NULL; } }
823  continue;
824  } else if ( ch=='P' && PeekMatch(sfd,"ath") ) {
825  int flags;
826  nlgetc(sfd); /* a */
827  nlgetc(sfd); /* t */
828  nlgetc(sfd); /* h */
829  if (PeekMatch(sfd,"Flags:")) {
830  nlgetc(sfd); /* F */
831  nlgetc(sfd); /* l */
832  nlgetc(sfd); /* a */
833  nlgetc(sfd); /* g */
834  nlgetc(sfd); /* s */
835  nlgetc(sfd); /* : */
836  getint(sfd,&flags);
837  if (cur != NULL) cur->is_clip_path = flags&1;
838  } else if (PeekMatch(sfd,"Start:")) {
839  nlgetc(sfd); /* S */
840  nlgetc(sfd); /* t */
841  nlgetc(sfd); /* a */
842  nlgetc(sfd); /* r */
843  nlgetc(sfd); /* t */
844  nlgetc(sfd); /* : */
845  getint(sfd,&flags);
846  if (cur != NULL) cur->start_offset = flags;
847  }
848  }
849  pt = NULL;
850  if ( ch=='l' || ch=='m' ) {
851  if ( sp>=2 ) {
852  current.x = stack[sp-2];
853  current.y = stack[sp-1];
854  sp -= 2;
855  pt = chunkalloc(sizeof(SplinePoint));
856  pt->me = current;
857  pt->noprevcp = true; pt->nonextcp = true;
858  if ( ch=='m' ) {
860  spl->first = spl->last = pt;
861  spl->start_offset = 0;
862  if ( cur!=NULL ) {
863  if ( SFDCloseCheck(cur,order2))
864  --ttfindex;
865  cur->next = spl;
866  } else
867  head = spl;
868  cur = spl;
869  } else {
870  if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
871  if ( cur->last->nextcpindex==0xfffe )
872  cur->last->nextcpindex = 0xffff;
873  SplineMake(cur->last,pt,order2);
874  cur->last->nonextcp = 1;
875  pt->noprevcp = 1;
876  cur->last = pt;
877  }
878  }
879  } else
880  sp = 0;
881  } else if ( ch=='c' ) {
882  if ( sp>=6 ) {
883  getint(sfd,&val);
884  have_read_val = 1;
885 
886 
887  current.x = stack[sp-2];
888  current.y = stack[sp-1];
889  real original_current_x = current.x;
891  {
892  // Find somewhere vacant to put the point.x for now
893  // we need to do this check in case we choose a point that is already
894  // on the spline and this connect back to that point instead of creating
895  // an open path
896  while( 1 )
897  {
898  real offset = 0.1;
899  current.x += offset;
901  {
902  break;
903  }
904  }
905  }
906 
907  if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
908  cur->last->nextcp.x = stack[sp-6];
909  cur->last->nextcp.y = stack[sp-5];
910  cur->last->nonextcp = false;
911  pt = chunkalloc(sizeof(SplinePoint));
912  pt->prevcp.x = stack[sp-4];
913  pt->prevcp.y = stack[sp-3];
914  pt->me = current;
915  pt->nonextcp = true;
916  if ( cur->last->nextcpindex==0xfffe )
917  cur->last->nextcpindex = ttfindex++;
918  else if ( cur->last->nextcpindex!=0xffff )
919  ttfindex = cur->last->nextcpindex+1;
920  SplineMake(cur->last,pt,order2);
921  cur->last = pt;
922  // pt->me is a copy of 'current' so we should now move
923  // the x coord of pt->me back to where it should be.
924  // The whole aim here is that this spline remains an open path
925  // when PTFLAG_FORCE_OPEN_PATH is set.
926  pt->me.x = original_current_x;
927  }
928 
929  // Move the point back to the same location it was
930  // but do not connect it back to the point that is
931  // already there.
933  {
934  current.x = original_current_x;
935  }
936 
937  sp -= 6;
938  } else
939  sp = 0;
940  }
941  if ( pt!=NULL ) {
942  if( !have_read_val )
943  getint(sfd,&val);
944 
945  pt->pointtype = (val & SFD_PTFLAG_TYPE_MASK);
946  pt->selected = (val & SFD_PTFLAG_IS_SELECTED) > 0;
947  pt->nextcpdef = (val & SFD_PTFLAG_NEXTCP_IS_DEFAULT) > 0;
948  pt->prevcpdef = (val & SFD_PTFLAG_PREVCP_IS_DEFAULT) > 0;
949  pt->roundx = (val & SFD_PTFLAG_ROUND_IN_X) > 0;
950  pt->roundy = (val & SFD_PTFLAG_ROUND_IN_Y) > 0;
951  pt->dontinterpolate = (val & SFD_PTFLAG_INTERPOLATE_NEVER) > 0;
952  if ( pt->prev!=NULL )
953  pt->prev->acceptableextrema = (val & SFD_PTFLAG_PREV_EXTREMA_MARKED_ACCEPTABLE) > 0;
954  else
955  lastacceptable = (val & SFD_PTFLAG_PREV_EXTREMA_MARKED_ACCEPTABLE) > 0;
956  if ( val&0x80 )
957  pt->ttfindex = 0xffff;
958  else
959  pt->ttfindex = ttfindex++;
960  pt->nextcpindex = 0xfffe;
961  ch = nlgetc(sfd);
962  if ( ch=='x' ) {
963  pt->hintmask = chunkalloc(sizeof(HintMask));
964  SFDGetHintMask(sfd,pt->hintmask);
965  } else if ( ch!=',' )
966  ungetc(ch,sfd);
967  else {
968  ch = nlgetc(sfd);
969  if ( ch==',' )
970  pt->ttfindex = 0xfffe;
971  else {
972  ungetc(ch,sfd);
973  getint(sfd,&val);
974  pt->ttfindex = val;
975  nlgetc(sfd); /* skip comma */
976  if ( val!=-1 )
977  ttfindex = val+1;
978  }
979  ch = nlgetc(sfd);
980  if ( ch=='\r' || ch=='\n' )
981  ungetc(ch,sfd);
982  else {
983  ungetc(ch,sfd);
984  getint(sfd,&val);
985  pt->nextcpindex = val;
986  if ( val!=-1 )
987  ttfindex = val+1;
988  }
989  }
990  }
991  }
992  if ( cur!=NULL )
993  SFDCloseCheck(cur,order2);
994  if ( lastacceptable && cur->last->prev!=NULL )
995  cur->last->prev->acceptableextrema = true;
996  getname(sfd,tok);
997 return( head );
998 }
999 
1001  SplineSet *ss;
1002  SplinePoint *sp;
1003  int pt,i, val, err;
1004  int ch;
1006  MinimumDistance *last, *md, *mdhead=NULL;
1007 
1008  for ( i=0; i<2; ++i ) {
1009  pt = 0;
1010  for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) {
1011  for ( sp=ss->first; ; ) {
1012  if ( mapping!=NULL ) mapping[pt] = sp;
1013  pt++;
1014  if ( sp->next == NULL )
1015  break;
1016  sp = sp->next->to;
1017  if ( sp==ss->first )
1018  break;
1019  }
1020  }
1021  if ( mapping==NULL )
1022  mapping = calloc(pt,sizeof(SplinePoint *));
1023  }
1024 
1025  last = NULL;
1026  for ( ch=nlgetc(sfd); ch!=EOF && ch!='\n'; ch=nlgetc(sfd)) {
1027  err = false;
1028  while ( isspace(ch) && ch!='\n' ) ch=nlgetc(sfd);
1029  if ( ch=='\n' )
1030  break;
1031  md = chunkalloc(sizeof(MinimumDistance));
1032  if ( ch=='x' ) md->x = true;
1033  getint(sfd,&val);
1034  if ( val<-1 || val>=pt ) {
1035  IError( "Minimum Distance specifies bad point (%d) in sfd file\n", val );
1036  err = true;
1037  } else if ( val!=-1 ) {
1038  md->sp1 = mapping[val];
1039  md->sp1->dontinterpolate = true;
1040  }
1041  ch = nlgetc(sfd);
1042  if ( ch!=',' ) {
1043  IError( "Minimum Distance lacks a comma where expected\n" );
1044  err = true;
1045  }
1046  getint(sfd,&val);
1047  if ( val<-1 || val>=pt ) {
1048  IError( "Minimum Distance specifies bad point (%d) in sfd file\n", val );
1049  err = true;
1050  } else if ( val!=-1 ) {
1051  md->sp2 = mapping[val];
1052  md->sp2->dontinterpolate = true;
1053  }
1054  if ( !err ) {
1055  if ( last!=NULL )
1056  last->next = md;
1057  last = md;
1058  } else
1059  chunkfree(md,sizeof(MinimumDistance));
1060  }
1061  free(mapping);
1062 
1063  /* Obsolete concept */
1064  MinimumDistancesFree(mdhead);
1065 }
1066 
1069  real begin, end;
1070  int ch;
1071 
1072  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1073  if ( ch=='G' && stem != NULL ) {
1074  stem->ghost = true;
1075  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1076  }
1077  if ( ch!='<' ) {
1078  ungetc(ch,sfd);
1079 return(NULL);
1080  }
1081  while ( getreal(sfd,&begin)==1 && getreal(sfd,&end)) {
1082  cur = chunkalloc(sizeof(HintInstance));
1083  cur->begin = begin;
1084  cur->end = end;
1085  if ( head == NULL )
1086  head = cur;
1087  else
1088  last->next = cur;
1089  last = cur;
1090  }
1091  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1092  if ( ch!='>' )
1093  ungetc(ch,sfd);
1094 return( head );
1095 }
1096 
1097 static StemInfo *SFDReadHints(FILE *sfd) {
1098  StemInfo *head=NULL, *last=NULL, *cur;
1099  real start, width;
1100 
1101  while ( getreal(sfd,&start)==1 && getreal(sfd,&width)) {
1102  cur = chunkalloc(sizeof(StemInfo));
1103  cur->start = start;
1104  cur->width = width;
1105  cur->where = SFDReadHintInstances(sfd,cur);
1106  if ( head == NULL )
1107  head = cur;
1108  else
1109  last->next = cur;
1110  last = cur;
1111  }
1112 return( head );
1113 }
1114 
1115 static DStemInfo *SFDReadDHints( SplineFont *sf,FILE *sfd,int old ) {
1116  DStemInfo *head=NULL, *last=NULL, *cur;
1117  int i;
1118  BasePoint bp[4], *bpref[4], left, right, unit;
1119  double rstartoff, rendoff, lendoff;
1120 
1121  if ( old ) {
1122  for ( i=0 ; i<4 ; i++ ) bpref[i] = &bp[i];
1123 
1124  while ( getreal( sfd,&bp[0].x ) && getreal( sfd,&bp[0].y ) &&
1125  getreal( sfd,&bp[1].x ) && getreal( sfd,&bp[1].y ) &&
1126  getreal( sfd,&bp[2].x ) && getreal( sfd,&bp[2].y ) &&
1127  getreal( sfd,&bp[3].x ) && getreal( sfd,&bp[3].y )) {
1128 
1129  /* Ensure point coordinates specified in the sfd file do */
1130  /* form a diagonal line */
1131  if ( PointsDiagonalable( sf,bpref,&unit )) {
1132  cur = chunkalloc( sizeof( DStemInfo ));
1133  cur->left = *bpref[0];
1134  cur->right = *bpref[1];
1135  cur->unit = unit;
1136  /* Generate a temporary hint instance, so that the hint can */
1137  /* be visible in charview even if subsequent rebuilding instances */
1138  /* fails (e. g. for composite characters) */
1139  cur->where = chunkalloc( sizeof( HintInstance ));
1140  rstartoff = ( cur->right.x - cur->left.x ) * cur->unit.x +
1141  ( cur->right.y - cur->left.y ) * cur->unit.y;
1142  rendoff = ( bpref[2]->x - cur->left.x ) * cur->unit.x +
1143  ( bpref[2]->y - cur->left.y ) * cur->unit.y;
1144  lendoff = ( bpref[3]->x - cur->left.x ) * cur->unit.x +
1145  ( bpref[3]->y - cur->left.y ) * cur->unit.y;
1146  cur->where->begin = ( rstartoff > 0 ) ? rstartoff : 0;
1147  cur->where->end = ( rendoff > lendoff ) ? lendoff : rendoff;
1148  MergeDStemInfo( sf,&head,cur );
1149  }
1150  }
1151  } else {
1152  while ( getreal( sfd,&left.x ) && getreal( sfd,&left.y ) &&
1153  getreal( sfd,&right.x ) && getreal( sfd,&right.y ) &&
1154  getreal( sfd,&unit.x ) && getreal( sfd,&unit.y )) {
1155  cur = chunkalloc( sizeof( DStemInfo ));
1156  cur->left = left;
1157  cur->right = right;
1158  cur->unit = unit;
1159  cur->where = SFDReadHintInstances( sfd,NULL );
1160  if ( head == NULL )
1161  head = cur;
1162  else
1163  last->next = cur;
1164  last = cur;
1165  }
1166  }
1167 return( head );
1168 }
1169 
1171  int i, junk, first, last, ch, len;
1172 
1173  while ( (ch=nlgetc(sfd))==' ' );
1174  if ( ch=='{' ) {
1175  while ( (ch=nlgetc(sfd))==' ' );
1176  if ( ch=='}' )
1177 return(NULL);
1178  else
1179  ungetc(ch,sfd);
1180  getint(sfd,&first);
1181  ch = nlgetc(sfd); /* Should be '-' */
1182  getint(sfd,&last);
1183  len = last-first+1;
1184  if ( len<=0 ) {
1185  IError( "Bad device table, invalid length.\n" );
1186 return(NULL);
1187  }
1188  if ( adjust==NULL )
1189  adjust = chunkalloc(sizeof(DeviceTable));
1190  adjust->first_pixel_size = first;
1191  adjust->last_pixel_size = last;
1192  adjust->corrections = malloc(len);
1193  for ( i=0; i<len; ++i ) {
1194  while ( (ch=nlgetc(sfd))==' ' );
1195  if ( ch!=',' ) ungetc(ch,sfd);
1196  getint(sfd,&junk);
1197  adjust->corrections[i] = junk;
1198  }
1199  while ( (ch=nlgetc(sfd))==' ' );
1200  if ( ch!='}' ) ungetc(ch,sfd);
1201  } else
1202  ungetc(ch,sfd);
1203 return( adjust );
1204 }
1205 
1207  int i, j, ch;
1208  ValDevTab vdt;
1209  char buf[4];
1210 
1211  memset(&vdt,0,sizeof(vdt));
1212  buf[3] = '\0';
1213  while ( (ch=nlgetc(sfd))==' ' );
1214  if ( ch=='[' ) {
1215  for ( i=0; i<4; ++i ) {
1216  while ( (ch=nlgetc(sfd))==' ' );
1217  if ( ch==']' )
1218  break;
1219  buf[0]=ch;
1220  for ( j=1; j<3; ++j ) buf[j]=nlgetc(sfd);
1221  while ( (ch=nlgetc(sfd))==' ' );
1222  if ( ch!='=' ) ungetc(ch,sfd);
1223  SFDReadDeviceTable(sfd,
1224  strcmp(buf,"ddx")==0 ? &vdt.xadjust :
1225  strcmp(buf,"ddy")==0 ? &vdt.yadjust :
1226  strcmp(buf,"ddh")==0 ? &vdt.xadv :
1227  strcmp(buf,"ddv")==0 ? &vdt.yadv :
1228  (&vdt.xadjust) + i );
1229  while ( (ch=nlgetc(sfd))==' ' );
1230  if ( ch!=']' ) ungetc(ch,sfd);
1231  else
1232  break;
1233  }
1234  if ( vdt.xadjust.corrections!=NULL || vdt.yadjust.corrections!=NULL ||
1235  vdt.xadv.corrections!=NULL || vdt.yadv.corrections!=NULL ) {
1236  ValDevTab *v = chunkalloc(sizeof(ValDevTab));
1237  *v = vdt;
1238 return( v );
1239  }
1240  } else
1241  ungetc(ch,sfd);
1242 return( NULL );
1243 }
1244 
1246 {
1247  AnchorPoint *ap = chunkalloc(sizeof(AnchorPoint));
1248  AnchorClass *an;
1249  char *name;
1250  char tok[200];
1251  int ch;
1252 
1253  name = SFDReadUTF7Str(sfd);
1254  if ( name==NULL ) {
1255  LogError(_("Anchor Point with no class name: %s"), sc->name );
1257 return( lastap );
1258  }
1259  for ( an=sc->parent->anchor; an!=NULL && strcmp(an->name,name)!=0; an=an->next );
1260  free(name);
1261  ap->anchor = an;
1262  getreal(sfd,&ap->me.x);
1263  getreal(sfd,&ap->me.y);
1264  ap->type = -1;
1265  if ( getname(sfd,tok)==1 ) {
1266  if ( strcmp(tok,"mark")==0 )
1267  ap->type = at_mark;
1268  else if ( strcmp(tok,"basechar")==0 )
1269  ap->type = at_basechar;
1270  else if ( strcmp(tok,"baselig")==0 )
1271  ap->type = at_baselig;
1272  else if ( strcmp(tok,"basemark")==0 )
1273  ap->type = at_basemark;
1274  else if ( strcmp(tok,"entry")==0 )
1275  ap->type = at_centry;
1276  else if ( strcmp(tok,"exit")==0 )
1277  ap->type = at_cexit;
1278  }
1279  getsint(sfd,&ap->lig_index);
1280  ch = nlgetc(sfd);
1281  ungetc(ch,sfd);
1282  if ( ch==' ' ) {
1283  SFDReadDeviceTable(sfd,&ap->xadjust);
1284  SFDReadDeviceTable(sfd,&ap->yadjust);
1285  ch = nlgetc(sfd);
1286  ungetc(ch,sfd);
1287  if ( isdigit(ch)) {
1288  getsint(sfd,(int16 *) &ap->ttf_pt_index);
1289  ap->has_ttf_pt = true;
1290  }
1291  }
1292  if ( ap->anchor==NULL || ap->type==-1 ) {
1293  LogError(_("Bad Anchor Point: %s"), sc->name );
1295 return( lastap );
1296  }
1297  if ( lastap==NULL )
1298  (*alist) = ap;
1299  else
1300  lastap->next = ap;
1301 
1302  return( ap );
1303 }
1304 
1305 static RefChar *SFDGetRef(FILE *sfd, int was_enc) {
1306  RefChar *rf;
1307  int temp=0, ch;
1308 
1309  rf = RefCharCreate();
1310  getint(sfd,&rf->orig_pos);
1311  rf->encoded = was_enc;
1312  if ( getint(sfd,&temp))
1313  rf->unicode_enc = temp;
1314  while ( isspace(ch=nlgetc(sfd)));
1315  if ( ch=='S' ) rf->selected = true;
1316  getreal(sfd,&rf->transform[0]);
1317  getreal(sfd,&rf->transform[1]);
1318  getreal(sfd,&rf->transform[2]);
1319  getreal(sfd,&rf->transform[3]);
1320  getreal(sfd,&rf->transform[4]);
1321  getreal(sfd,&rf->transform[5]);
1322  while ( (ch=nlgetc(sfd))==' ');
1323  ungetc(ch,sfd);
1324  if ( isdigit(ch) ) {
1325  getint(sfd,&temp);
1326  rf->use_my_metrics = temp&1;
1327  rf->round_translation_to_grid = (temp&2)?1:0;
1328  rf->point_match = (temp&4)?1:0;
1329  if ( rf->point_match ) {
1330  getsint(sfd,(int16 *) &rf->match_pt_base);
1331  getsint(sfd,(int16 *) &rf->match_pt_ref);
1332  while ( (ch=nlgetc(sfd))==' ');
1333  if ( ch=='O' )
1334  rf->point_match_out_of_date = true;
1335  else
1336  ungetc(ch,sfd);
1337  }
1338  }
1339 return( rf );
1340 }
1341 
1342 /* I used to create multiple ligatures by putting ";" between them */
1343 /* that is the component string for "ffi" was "ff i ; f f i" */
1344 /* Now I want to have separate ligature structures for each */
1346  char *pt;
1347  PST1 *new, *last=liga;
1348  while ( (pt = strrchr(liga->pst.u.lig.components,';'))!=NULL ) {
1349  new = chunkalloc(sizeof( PST1 ));
1350  *new = *liga;
1351  new->pst.u.lig.components = copy(pt+1);
1352  last->pst.next = (PST *) new;
1353  last = new;
1354  *pt = '\0';
1355  }
1356 return( last );
1357 }
1358 
1359 #ifdef FONTFORGE_CONFIG_CVT_OLD_MAC_FEATURES
1360 static struct { int feature, setting; uint32 tag; } formertags[] = {
1361  { 1, 6, CHR('M','L','O','G') },
1362  { 1, 8, CHR('M','R','E','B') },
1363  { 1, 10, CHR('M','D','L','G') },
1364  { 1, 12, CHR('M','S','L','G') },
1365  { 1, 14, CHR('M','A','L','G') },
1366  { 8, 0, CHR('M','S','W','I') },
1367  { 8, 2, CHR('M','S','W','F') },
1368  { 8, 4, CHR('M','S','L','I') },
1369  { 8, 6, CHR('M','S','L','F') },
1370  { 8, 8, CHR('M','S','N','F') },
1371  { 22, 1, CHR('M','W','I','D') },
1372  { 27, 1, CHR('M','U','C','M') },
1373  { 103, 2, CHR('M','W','I','D') },
1374  { -1, -1, 0xffffffff },
1375 };
1376 
1377 static void CvtOldMacFeature(PST1 *pst) {
1378  int i;
1379 
1380  if ( pst->macfeature )
1381 return;
1382  for ( i=0; formertags[i].feature!=-1 ; ++i ) {
1383  if ( pst->tag == formertags[i].tag ) {
1384  pst->macfeature = true;
1385  pst->tag = (formertags[i].feature<<16) | formertags[i].setting;
1386 return;
1387  }
1388  }
1389 }
1390 #endif
1391 
1392 static void SFDSetEncMap(SplineFont *sf,int orig_pos,int enc) {
1393  EncMap *map = sf->map;
1394 
1395  if ( map==NULL )
1396 return;
1397 
1398  if ( orig_pos>=map->backmax ) {
1399  int old = map->backmax;
1400  map->backmax = orig_pos+10;
1401  map->backmap = realloc(map->backmap,map->backmax*sizeof(int));
1402  memset(map->backmap+old,-1,(map->backmax-old)*sizeof(int));
1403  }
1404  if ( map->backmap[orig_pos] == -1 ) /* backmap will not be unique if multiple encodings come from same glyph */
1405  map->backmap[orig_pos] = enc;
1406  if ( enc>=map->encmax ) {
1407  int old = map->encmax;
1408  map->encmax = enc+10;
1409  map->map = realloc(map->map,map->encmax*sizeof(int));
1410  memset(map->map+old,-1,(map->encmax-old)*sizeof(int));
1411  }
1412  if ( enc>=map->enccount )
1413  map->enccount = enc+1;
1414  if ( enc!=-1 )
1415  map->map[enc] = orig_pos;
1416 }
1417 
1419  SplineSet *cur;
1420  SplinePoint *sp;
1421  /* We used not to store the dontinterpolate bit. We used to use the */
1422  /* presence or absence of instructions as that flag */
1423 
1424  if ( sc->ttf_instrs_len!=0 ) {
1425  for ( cur=sc->layers[ly_fore].splines; cur!=NULL; cur=cur->next ) {
1426  for ( sp=cur->first; ; ) {
1427  if ( sp->ttfindex!=0xffff && SPInterpolate(sp))
1428  sp->dontinterpolate = true;
1429  if ( sp->next==NULL )
1430  break;
1431  sp=sp->next->to;
1432  if ( sp==cur->first )
1433  break;
1434  }
1435  }
1436  }
1437 }
1438 
1439 static void SFDParseMathValueRecord(FILE *sfd,int16 *value,DeviceTable **devtab) {
1440  getsint(sfd,value);
1441  *devtab = SFDReadDeviceTable(sfd,NULL);
1442 }
1443 
1445  struct glyphvariants *gv, char *tok) {
1446  int i;
1447 
1448  if ( gv==NULL )
1449  gv = chunkalloc(sizeof(struct glyphvariants));
1450  getint(sfd,&gv->part_cnt);
1451  gv->parts = calloc(gv->part_cnt,sizeof(struct gv_part));
1452  for ( i=0; i<gv->part_cnt; ++i ) {
1453  int temp, ch;
1454  getname(sfd,tok);
1455  gv->parts[i].component = copy(tok);
1456  while ( (ch=nlgetc(sfd))==' ' );
1457  if ( ch!='%' ) ungetc(ch,sfd);
1458  getint(sfd,&temp);
1459  gv->parts[i].is_extender = temp;
1460  while ( (ch=nlgetc(sfd))==' ' );
1461  if ( ch!=',' ) ungetc(ch,sfd);
1462  getint(sfd,&temp);
1464  while ( (ch=nlgetc(sfd))==' ' );
1465  if ( ch!=',' ) ungetc(ch,sfd);
1466  getint(sfd,&temp);
1467  gv->parts[i].endConnectorLength = temp;
1468  while ( (ch=nlgetc(sfd))==' ' );
1469  if ( ch!=',' ) ungetc(ch,sfd);
1470  getint(sfd,&temp);
1471  gv->parts[i].fullAdvance = temp;
1472  }
1473 return( gv );
1474 }
1475 
1476 static void SFDParseVertexKern(FILE *sfd, struct mathkernvertex *vertex) {
1477  int i,ch;
1478 
1479  getint(sfd,&vertex->cnt);
1480  vertex->mkd = calloc(vertex->cnt,sizeof(struct mathkerndata));
1481  for ( i=0; i<vertex->cnt; ++i ) {
1482  SFDParseMathValueRecord(sfd,&vertex->mkd[i].height,&vertex->mkd[i].height_adjusts);
1483  while ( (ch=nlgetc(sfd))==' ' );
1484  if ( ch!=EOF && ch!=',' )
1485  ungetc(ch,sfd);
1486  SFDParseMathValueRecord(sfd,&vertex->mkd[i].kern,&vertex->mkd[i].kern_adjusts);
1487  }
1488 }
1489 
1490 static struct gradient *SFDParseGradient(FILE *sfd,char *tok) {
1491  struct gradient *grad = chunkalloc(sizeof(struct gradient));
1492  int ch, i;
1493 
1494  getreal(sfd,&grad->start.x);
1495  while ( isspace(ch=nlgetc(sfd)));
1496  if ( ch!=';' ) ungetc(ch,sfd);
1497  getreal(sfd,&grad->start.y);
1498 
1499  getreal(sfd,&grad->stop.x);
1500  while ( isspace(ch=nlgetc(sfd)));
1501  if ( ch!=';' ) ungetc(ch,sfd);
1502  getreal(sfd,&grad->stop.y);
1503 
1504  getreal(sfd,&grad->radius);
1505 
1506  getname(sfd,tok);
1507  for ( i=0; spreads[i]!=NULL; ++i )
1508  if ( strmatch(spreads[i],tok)==0 )
1509  break;
1510  if ( spreads[i]==NULL ) i=0;
1511  grad->sm = i;
1512 
1513  getint(sfd,&grad->stop_cnt);
1514  grad->grad_stops = calloc(grad->stop_cnt,sizeof(struct grad_stops));
1515  for ( i=0; i<grad->stop_cnt; ++i ) {
1516  while ( isspace(ch=nlgetc(sfd)));
1517  if ( ch!='{' ) ungetc(ch,sfd);
1518  getreal( sfd, &grad->grad_stops[i].offset );
1519  gethex( sfd, &grad->grad_stops[i].col );
1520  getreal( sfd, &grad->grad_stops[i].opacity );
1521  while ( isspace(ch=nlgetc(sfd)));
1522  if ( ch!='}' ) ungetc(ch,sfd);
1523  }
1524 return( grad );
1525 }
1526 
1527 static struct pattern *SFDParsePattern(FILE *sfd,char *tok) {
1528  struct pattern *pat = chunkalloc(sizeof(struct pattern));
1529  int ch;
1530 
1531  getname(sfd,tok);
1532  pat->pattern = copy(tok);
1533 
1534  getreal(sfd,&pat->width);
1535  while ( isspace(ch=nlgetc(sfd)));
1536  if ( ch!=';' ) ungetc(ch,sfd);
1537  getreal(sfd,&pat->height);
1538 
1539  while ( isspace(ch=nlgetc(sfd)));
1540  if ( ch!='[' ) ungetc(ch,sfd);
1541  getreal(sfd,&pat->transform[0]);
1542  getreal(sfd,&pat->transform[1]);
1543  getreal(sfd,&pat->transform[2]);
1544  getreal(sfd,&pat->transform[3]);
1545  getreal(sfd,&pat->transform[4]);
1546  getreal(sfd,&pat->transform[5]);
1547  while ( isspace(ch=nlgetc(sfd)));
1548  if ( ch!=']' ) ungetc(ch,sfd);
1549 return( pat );
1550 }
1551 
1552 
1553 static int orig_pos;
1554 
1555 static SplineChar *SFDGetChar(FILE *sfd,SplineFont *sf, int had_sf_layer_cnt) {
1556  SplineChar *sc;
1557  char tok[2000], ch;
1558  RefChar *lastr=NULL, *ref;
1559  AnchorPoint *lastap = NULL;
1560  int isliga = 0, ispos, issubs=0, ismult=0, islcar=0, ispair=0, temp, i;
1561  PST *last = NULL;
1562  uint32 script = 0;
1563  int current_layer = ly_fore;
1564  int had_old_dstems = false;
1565  SplineFont *sli_sf = sf->cidmaster ? sf->cidmaster : sf;
1566  struct altuni *altuni;
1567  int oldback = false;
1568 
1569  if ( getname(sfd,tok)!=1 )
1570 return( NULL );
1571  if ( strcmp(tok,"StartChar:")!=0 )
1572 return( NULL );
1573  while ( isspace(ch=nlgetc(sfd)));
1574  ungetc(ch,sfd);
1576  if ( ch!='"' ) {
1577  if ( getname(sfd,tok)!=1 ) {
1578  SplineCharFree(sc);
1579 return( NULL );
1580  }
1581  sc->name = copy(tok);
1582  } else {
1583  sc->name = SFDReadUTF7Str(sfd);
1584  if ( sc->name==NULL ) {
1585  SplineCharFree(sc);
1586 return( NULL );
1587  }
1588  }
1589  sc->vwidth = sf->ascent+sf->descent;
1590  sc->parent = sf;
1591  while ( 1 ) {
1592  if ( getname(sfd,tok)!=1 ) {
1593  SplineCharFree(sc);
1594 return( NULL );
1595  }
1596  if ( strmatch(tok,"Encoding:")==0 ) {
1597  int enc;
1598  getint(sfd,&enc);
1599  getint(sfd,&sc->unicodeenc);
1600  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1601  ungetc(ch,sfd);
1602  if ( ch!='\n' && ch!='\r' ) {
1603  getint(sfd,&sc->orig_pos);
1604  if ( sc->orig_pos==65535 )
1605  sc->orig_pos = orig_pos++;
1606  /* An old mark meaning: "I don't know" */
1607  if ( sc->orig_pos<sf->glyphcnt && sf->glyphs[sc->orig_pos]!=NULL )
1608  sc->orig_pos = sf->glyphcnt;
1609  if ( sc->orig_pos>=sf->glyphcnt ) {
1610  if ( sc->orig_pos>=sf->glyphmax )
1611  sf->glyphs = realloc(sf->glyphs,(sf->glyphmax = sc->orig_pos+10)*sizeof(SplineChar *));
1612  memset(sf->glyphs+sf->glyphcnt,0,(sc->orig_pos+1-sf->glyphcnt)*sizeof(SplineChar *));
1613  sf->glyphcnt = sc->orig_pos+1;
1614  }
1615  if ( sc->orig_pos+1 > orig_pos )
1616  orig_pos = sc->orig_pos+1;
1617  } else if ( sf->cidmaster!=NULL ) { /* In cid fonts the orig_pos is just the cid */
1618  sc->orig_pos = enc;
1619  } else {
1620  sc->orig_pos = orig_pos++;
1621  }
1622  SFDSetEncMap(sf,sc->orig_pos,enc);
1623  } else if ( strmatch(tok,"AltUni:")==0 ) {
1624  int uni;
1625  while ( getint(sfd,&uni)==1 ) {
1626  altuni = chunkalloc(sizeof(struct altuni));
1627  altuni->unienc = uni;
1628  altuni->vs = -1;
1629  altuni->fid = 0;
1630  altuni->next = sc->altuni;
1631  sc->altuni = altuni;
1632  }
1633  } else if ( strmatch(tok,"AltUni2:")==0 ) {
1634  uint32 uni[3];
1635  while ( gethexints(sfd,uni,3) ) {
1636  altuni = chunkalloc(sizeof(struct altuni));
1637  altuni->unienc = uni[0];
1638  altuni->vs = uni[1];
1639  altuni->fid = uni[2];
1640  altuni->next = sc->altuni;
1641  sc->altuni = altuni;
1642  }
1643  } else if ( strmatch(tok,"OldEncoding:")==0 ) {
1644  int old_enc; /* Obsolete info */
1645  getint(sfd,&old_enc);
1646  } else if ( strmatch(tok,"Script:")==0 ) {
1647  /* Obsolete. But still used for parsing obsolete ligature/subs tags */
1648  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1649  if ( ch=='\n' || ch=='\r' )
1650  script = 0;
1651  else {
1652  ungetc(ch,sfd);
1653  script = gettag(sfd);
1654  }
1655  } else if ( strmatch(tok,"GlifName:")==0 ) {
1656  while ( isspace(ch=nlgetc(sfd)));
1657  ungetc(ch,sfd);
1658  if ( ch!='"' ) {
1659  if ( getname(sfd,tok)!=1 ) {
1660  LogError(_("Invalid glif name.\n"));
1661  }
1662  sc->glif_name = copy(tok);
1663  } else {
1664  sc->glif_name = SFDReadUTF7Str(sfd);
1665  if ( sc->glif_name==NULL ) {
1666  LogError(_("Invalid glif name.\n"));
1667  }
1668  }
1669  } else if ( strmatch(tok,"Width:")==0 ) {
1670  getsint(sfd,&sc->width);
1671  } else if ( strmatch(tok,"VWidth:")==0 ) {
1672  getsint(sfd,&sc->vwidth);
1673  } else if ( strmatch(tok,"GlyphClass:")==0 ) {
1674  getint(sfd,&temp);
1675  sc->glyph_class = temp;
1676  } else if ( strmatch(tok,"UnlinkRmOvrlpSave:")==0 ) {
1677  getint(sfd,&temp);
1678  sc->unlink_rm_ovrlp_save_undo = temp;
1679  } else if ( strmatch(tok,"InSpiro:")==0 ) {
1680  getint(sfd,&temp);
1681  sc->inspiro = temp;
1682  } else if ( strmatch(tok,"LigCaretCntFixed:")==0 ) {
1683  getint(sfd,&temp);
1684  sc->lig_caret_cnt_fixed = temp;
1685  } else if ( strmatch(tok,"Flags:")==0 ) {
1686  while ( isspace(ch=nlgetc(sfd)) && ch!='\n' && ch!='\r');
1687  while ( ch!='\n' && ch!='\r' ) {
1688  if ( ch=='H' ) sc->changedsincelasthinted=true;
1689  else if ( ch=='M' ) sc->manualhints = true;
1690  else if ( ch=='W' ) sc->widthset = true;
1691  else if ( ch=='O' ) sc->wasopen = true;
1692  else if ( ch=='I' ) sc->instructions_out_of_date = true;
1693  ch = nlgetc(sfd);
1694  }
1695  if ( sf->multilayer || sf->strokedfont || sc->layers[ly_fore].order2 )
1696  sc->changedsincelasthinted = false;
1697  } else if ( strmatch(tok,"TeX:")==0 ) {
1698  getsint(sfd,&sc->tex_height);
1699  getsint(sfd,&sc->tex_depth);
1700  while ( isspace(ch=nlgetc(sfd)) && ch!='\n' && ch!='\r');
1701  ungetc(ch,sfd);
1702  if ( ch!='\n' && ch!='\r' ) {
1703  int16 old_tex;
1704  /* Used to store two extra values here */
1705  getsint(sfd,&old_tex);
1706  getsint(sfd,&old_tex);
1707  if ( sc->tex_height==0 && sc->tex_depth==0 ) /* Fixup old bug */
1708  sc->tex_height = sc->tex_depth = TEX_UNDEF;
1709  }
1710  } else if ( strmatch(tok,"ItalicCorrection:")==0 ) {
1711  SFDParseMathValueRecord(sfd,&sc->italic_correction,&sc->italic_adjusts);
1712  } else if ( strmatch(tok,"TopAccentHorizontal:")==0 ) {
1713  SFDParseMathValueRecord(sfd,&sc->top_accent_horiz,&sc->top_accent_adjusts);
1714  } else if ( strmatch(tok,"GlyphCompositionVerticalIC:")==0 ) {
1715  if ( sc->vert_variants==NULL )
1716  sc->vert_variants = chunkalloc(sizeof(struct glyphvariants));
1717  SFDParseMathValueRecord(sfd,&sc->vert_variants->italic_correction,&sc->vert_variants->italic_adjusts);
1718  } else if ( strmatch(tok,"GlyphCompositionHorizontalIC:")==0 ) {
1719  if ( sc->horiz_variants==NULL )
1720  sc->horiz_variants = chunkalloc(sizeof(struct glyphvariants));
1721  SFDParseMathValueRecord(sfd,&sc->horiz_variants->italic_correction,&sc->horiz_variants->italic_adjusts);
1722  } else if ( strmatch(tok,"IsExtendedShape:")==0 ) {
1723  int temp;
1724  getint(sfd,&temp);
1725  sc->is_extended_shape = temp;
1726  } else if ( strmatch(tok,"GlyphVariantsVertical:")==0 ) {
1727  if ( sc->vert_variants==NULL )
1728  sc->vert_variants = chunkalloc(sizeof(struct glyphvariants));
1729  geteol(sfd,tok);
1730  sc->vert_variants->variants = copy(tok);
1731  } else if ( strmatch(tok,"GlyphVariantsHorizontal:")==0 ) {
1732  if ( sc->horiz_variants==NULL )
1733  sc->horiz_variants = chunkalloc(sizeof(struct glyphvariants));
1734  geteol(sfd,tok);
1735  sc->horiz_variants->variants = copy(tok);
1736  } else if ( strmatch(tok,"GlyphCompositionVertical:")==0 ) {
1737  sc->vert_variants = SFDParseGlyphComposition(sfd, sc->vert_variants,tok);
1738  } else if ( strmatch(tok,"GlyphCompositionHorizontal:")==0 ) {
1739  sc->horiz_variants = SFDParseGlyphComposition(sfd, sc->horiz_variants,tok);
1740  } else if ( strmatch(tok,"TopRightVertex:")==0 ) {
1741  if ( sc->mathkern==NULL )
1742  sc->mathkern = chunkalloc(sizeof(struct mathkern));
1743  SFDParseVertexKern(sfd, &sc->mathkern->top_right);
1744  } else if ( strmatch(tok,"TopLeftVertex:")==0 ) {
1745  if ( sc->mathkern==NULL )
1746  sc->mathkern = chunkalloc(sizeof(struct mathkern));
1747  SFDParseVertexKern(sfd, &sc->mathkern->top_left);
1748  } else if ( strmatch(tok,"BottomRightVertex:")==0 ) {
1749  if ( sc->mathkern==NULL )
1750  sc->mathkern = chunkalloc(sizeof(struct mathkern));
1751  SFDParseVertexKern(sfd, &sc->mathkern->bottom_right);
1752  } else if ( strmatch(tok,"BottomLeftVertex:")==0 ) {
1753  if ( sc->mathkern==NULL )
1754  sc->mathkern = chunkalloc(sizeof(struct mathkern));
1755  SFDParseVertexKern(sfd, &sc->mathkern->bottom_left);
1756 #if HANYANG
1757  } else if ( strmatch(tok,"CompositionUnit:")==0 ) {
1758  getsint(sfd,&sc->jamo);
1759  getsint(sfd,&sc->varient);
1760  sc->compositionunit = true;
1761 #endif
1762  } else if ( strmatch(tok,"HStem:")==0 ) {
1763  sc->hstem = SFDReadHints(sfd);
1764  sc->hconflicts = StemListAnyConflicts(sc->hstem);
1765  } else if ( strmatch(tok,"VStem:")==0 ) {
1766  sc->vstem = SFDReadHints(sfd);
1767  sc->vconflicts = StemListAnyConflicts(sc->vstem);
1768  } else if ( strmatch(tok,"DStem:")==0 ) {
1769  sc->dstem = SFDReadDHints( sc->parent,sfd,true );
1770  had_old_dstems = true;
1771  } else if ( strmatch(tok,"DStem2:")==0 ) {
1772  sc->dstem = SFDReadDHints( sc->parent,sfd,false );
1773  } else if ( strmatch(tok,"CounterMasks:")==0 ) {
1774  getsint(sfd,&sc->countermask_cnt);
1775  sc->countermasks = calloc(sc->countermask_cnt,sizeof(HintMask));
1776  for ( i=0; i<sc->countermask_cnt; ++i ) {
1777  int ch;
1778  while ( (ch=nlgetc(sfd))==' ' );
1779  ungetc(ch,sfd);
1780  SFDGetHintMask(sfd,&sc->countermasks[i]);
1781  }
1782  } else if ( strmatch(tok,"AnchorPoint:")==0 ) {
1783  lastap = SFDReadAnchorPoints(sfd,sc,&sc->anchor,lastap);
1784  } else if ( strmatch(tok,"Fore")==0 ) {
1785  while ( isspace(ch = nlgetc(sfd)));
1786  ungetc(ch,sfd);
1787  if ( ch!='I' && ch!='R' && ch!='S' && ch!='V' && ch!=' ' && ch!='\n' &&
1788  !PeekMatch(sfd, "Pickled") && !PeekMatch(sfd, "EndChar") &&
1789  !PeekMatch(sfd, "Fore") && !PeekMatch(sfd, "Back") && !PeekMatch(sfd, "Layer") ) {
1790  /* Old format, without a SplineSet token */
1791  sc->layers[ly_fore].splines = SFDGetSplineSet(sfd,sc->layers[ly_fore].order2);
1792  }
1793  current_layer = ly_fore;
1794  } else if ( strmatch(tok,"MinimumDistance:")==0 ) {
1796  } else if ( strmatch(tok,"Validated:")==0 ) {
1797  getsint(sfd,(int16 *) &sc->layers[current_layer].validation_state);
1798  } else if ( strmatch(tok,"Back")==0 ) {
1799  while ( isspace(ch=nlgetc(sfd)));
1800  ungetc(ch,sfd);
1801  if ( ch!='I' && ch!='R' && ch!='S' && ch!='V' && ch!=' ' && ch!='\n' &&
1802  !PeekMatch(sfd, "Pickled") && !PeekMatch(sfd, "EndChar") &&
1803  !PeekMatch(sfd, "Fore") && !PeekMatch(sfd, "Back") && !PeekMatch(sfd, "Layer") ) {
1804  /* Old format, without a SplineSet token */
1805  sc->layers[ly_back].splines = SFDGetSplineSet(sfd,sc->layers[ly_back].order2);
1806  oldback = true;
1807  }
1808  current_layer = ly_back;
1809  } else if ( strmatch(tok,"LayerCount:")==0 ) {
1810  getint(sfd,&temp);
1811  if ( temp>sc->layer_cnt ) {
1812  sc->layers = realloc(sc->layers,temp*sizeof(Layer));
1813  memset(sc->layers+sc->layer_cnt,0,(temp-sc->layer_cnt)*sizeof(Layer));
1814  }
1815  sc->layer_cnt = temp;
1816  current_layer = ly_fore;
1817  } else if ( strmatch(tok,"Layer:")==0 ) {
1818  int layer;
1819  int dofill, dostroke, fillfirst, linejoin, linecap;
1820  uint32 fillcol, strokecol;
1821  real fillopacity, strokeopacity, strokewidth, trans[4];
1822  DashType dashes[DASH_MAX];
1823  int i;
1824  getint(sfd,&layer);
1825  if ( layer>=sc->layer_cnt ) {
1826  sc->layers = realloc(sc->layers,(layer+1)*sizeof(Layer));
1827  memset(sc->layers+sc->layer_cnt,0,(layer+1-sc->layer_cnt)*sizeof(Layer));
1828  }
1829  if ( sc->parent->multilayer ) {
1830  getint(sfd,&dofill);
1831  getint(sfd,&dostroke);
1832  getint(sfd,&fillfirst);
1833  gethex(sfd,&fillcol);
1834  getreal(sfd,&fillopacity);
1835  gethex(sfd,&strokecol);
1836  getreal(sfd,&strokeopacity);
1837  getreal(sfd,&strokewidth);
1838  getname(sfd,tok);
1839  for ( i=0; joins[i]!=NULL; ++i )
1840  if ( strmatch(joins[i],tok)==0 )
1841  break;
1842  if ( joins[i]==NULL ) --i;
1843  linejoin = i;
1844  getname(sfd,tok);
1845  for ( i=0; caps[i]!=NULL; ++i )
1846  if ( strmatch(caps[i],tok)==0 )
1847  break;
1848  if ( caps[i]==NULL ) --i;
1849  linecap = i;
1850  while ( (ch=nlgetc(sfd))==' ' || ch=='[' );
1851  ungetc(ch,sfd);
1852  getreal(sfd,&trans[0]);
1853  getreal(sfd,&trans[1]);
1854  getreal(sfd,&trans[2]);
1855  getreal(sfd,&trans[3]);
1856  while ( (ch=nlgetc(sfd))==' ' || ch==']' );
1857  if ( ch=='[' ) {
1858  for ( i=0;; ++i ) { int temp;
1859  if ( !getint(sfd,&temp) )
1860  break;
1861  else if ( i<DASH_MAX )
1862  dashes[i] = temp;
1863  }
1864  if ( i<DASH_MAX )
1865  dashes[i] = 0;
1866  } else {
1867  ungetc(ch,sfd);
1868  memset(dashes,0,sizeof(dashes));
1869  }
1870  sc->layers[layer].dofill = dofill;
1871  sc->layers[layer].dostroke = dostroke;
1872  sc->layers[layer].fillfirst = fillfirst;
1873  sc->layers[layer].fill_brush.col = fillcol;
1874  sc->layers[layer].fill_brush.opacity = fillopacity;
1875  sc->layers[layer].stroke_pen.brush.col = strokecol;
1876  sc->layers[layer].stroke_pen.brush.opacity = strokeopacity;
1877  sc->layers[layer].stroke_pen.width = strokewidth;
1878  sc->layers[layer].stroke_pen.linejoin = linejoin;
1879  sc->layers[layer].stroke_pen.linecap = linecap;
1880  memcpy(sc->layers[layer].stroke_pen.dashes,dashes,sizeof(dashes));
1881  memcpy(sc->layers[layer].stroke_pen.trans,trans,sizeof(trans));
1882  }
1883  current_layer = layer;
1884  lastr = NULL;
1885  } else if ( strmatch(tok,"FillGradient:")==0 ) {
1886  sc->layers[current_layer].fill_brush.gradient = SFDParseGradient(sfd,tok);
1887  } else if ( strmatch(tok,"FillPattern:")==0 ) {
1888  sc->layers[current_layer].fill_brush.pattern = SFDParsePattern(sfd,tok);
1889  } else if ( strmatch(tok,"StrokeGradient:")==0 ) {
1890  sc->layers[current_layer].stroke_pen.brush.gradient = SFDParseGradient(sfd,tok);
1891  } else if ( strmatch(tok,"StrokePattern:")==0 ) {
1892  sc->layers[current_layer].stroke_pen.brush.pattern = SFDParsePattern(sfd,tok);
1893  } else if ( strmatch(tok,"SplineSet")==0 ) {
1894  sc->layers[current_layer].splines = SFDGetSplineSet(sfd,sc->layers[current_layer].order2);
1895  } else if ( strmatch(tok,"Ref:")==0 || strmatch(tok,"Refer:")==0 ) {
1896  /* I should be depending on the version number here, but I made */
1897  /* a mistake and bumped the version too late. So the version is */
1898  /* not an accurate mark, but the presence of a LayerCount keyword*/
1899  /* in the font is an good mark. Before the LayerCount was added */
1900  /* (version 2) only the foreground layer could have references */
1901  /* after that (eventually version 3) any layer could. */
1902  if ( oldback || !had_sf_layer_cnt ) current_layer = ly_fore;
1903  ref = SFDGetRef(sfd,strmatch(tok,"Ref:")==0);
1904  if ( sc->layers[current_layer].refs==NULL )
1905  sc->layers[current_layer].refs = ref;
1906  else
1907  lastr->next = ref;
1908  lastr = ref;
1909  } else if ( strmatch(tok,"PickledData:")==0 ) {
1910  if (current_layer < sc->layer_cnt) {
1911  sc->layers[current_layer].python_persistent = SFDUnPickle(sfd, 0);
1912  sc->layers[current_layer].python_persistent_has_lists = 0;
1913  }
1914  } else if ( strmatch(tok,"PickledDataWithLists:")==0 ) {
1915  if (current_layer < sc->layer_cnt) {
1916  sc->layers[current_layer].python_persistent = SFDUnPickle(sfd, 1);
1917  sc->layers[current_layer].python_persistent_has_lists = 1;
1918  }
1919  } else if ( strmatch(tok,"OrigType1:")==0 ) { /* Accept, slurp, ignore contents */
1920  SFDGetType1(sfd);
1921  } else if ( strmatch(tok,"TtfInstrs:")==0 ) { /* Binary format */
1922  SFDGetTtfInstrs(sfd,sc);
1923  } else if ( strmatch(tok,"TtInstrs:")==0 ) { /* ASCII format */
1924  SFDGetTtInstrs(sfd,sc);
1925  } else if ( strmatch(tok,"Kerns2:")==0 ||
1926  strmatch(tok,"VKerns2:")==0 ) {
1927  KernPair *kp, *last=NULL;
1928  int isv = *tok=='V';
1929  int off, index;
1930  struct lookup_subtable *sub;
1931 
1932  while ( fscanf(sfd,"%d %d", &index, &off )==2 ) {
1934  if ( sub==NULL ) {
1935  LogError(_("KernPair with no subtable name.\n"));
1936  break;
1937  }
1938  kp = chunkalloc(sizeof(KernPair1));
1939  kp->sc = (SplineChar *) (intpt) index;
1940  kp->kcid = true;
1941  kp->off = off;
1942  kp->subtable = sub;
1943  kp->next = NULL;
1944  while ( (ch=nlgetc(sfd))==' ' );
1945  ungetc(ch,sfd);
1946  if ( ch=='{' ) {
1947  kp->adjust = SFDReadDeviceTable(sfd, NULL);
1948  }
1949  if ( last != NULL )
1950  last->next = kp;
1951  else if ( isv )
1952  sc->vkerns = kp;
1953  else
1954  sc->kerns = kp;
1955  last = kp;
1956  }
1957  } else if ( (ispos = (strmatch(tok,"Position:")==0)) ||
1958  ( ispos = (strmatch(tok,"Position2:")==0)) ||
1959  ( ispair = (strmatch(tok,"PairPos:")==0)) ||
1960  ( ispair = (strmatch(tok,"PairPos2:")==0)) ||
1961  ( islcar = (strmatch(tok,"LCarets:")==0)) ||
1962  ( islcar = (strmatch(tok,"LCarets2:")==0)) ||
1963  ( isliga = (strmatch(tok,"Ligature:")==0)) ||
1964  ( isliga = (strmatch(tok,"Ligature2:")==0)) ||
1965  ( issubs = (strmatch(tok,"Substitution:")==0)) ||
1966  ( issubs = (strmatch(tok,"Substitution2:")==0)) ||
1967  ( ismult = (strmatch(tok,"MultipleSubs:")==0)) ||
1968  ( ismult = (strmatch(tok,"MultipleSubs2:")==0)) ||
1969  strmatch(tok,"AlternateSubs:")==0 ||
1970  strmatch(tok,"AlternateSubs2:")==0 ) {
1971  PST *pst;
1972  int old, type;
1973  type = ispos ? pst_position :
1974  ispair ? pst_pair :
1975  islcar ? pst_lcaret :
1976  isliga ? pst_ligature :
1977  issubs ? pst_substitution :
1978  ismult ? pst_multiple :
1979  pst_alternate;
1980  if ( strchr(tok,'2')!=NULL ) {
1981  old = false;
1982  pst = chunkalloc(sizeof(PST));
1983  if ( type!=pst_lcaret )
1985  } else {
1986  old = true;
1987  pst = chunkalloc(sizeof(PST1));
1988  ((PST1 *) pst)->tag = CHR('l','i','g','a');
1989  ((PST1 *) pst)->script_lang_index = 0xffff;
1990  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1991  if ( isdigit(ch)) {
1992  int temp;
1993  ungetc(ch,sfd);
1994  getint(sfd,&temp);
1995  ((PST1 *) pst)->flags = temp;
1996  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
1997  } else
1998  ((PST1 *) pst)->flags = 0 /*PSTDefaultFlags(type,sc)*/;
1999  if ( isdigit(ch)) {
2000  ungetc(ch,sfd);
2001  getusint(sfd,&((PST1 *) pst)->script_lang_index);
2002  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
2003  } else
2004  ((PST1 *) pst)->script_lang_index = SFFindBiggestScriptLangIndex(sf,
2006  if ( ch=='\'' ) {
2007  ungetc(ch,sfd);
2008  ((PST1 *) pst)->tag = gettag(sfd);
2009  } else if ( ch=='<' ) {
2010  getint(sfd,&temp);
2011  ((PST1 *) pst)->tag = temp<<16;
2012  nlgetc(sfd); /* comma */
2013  getint(sfd,&temp);
2014  ((PST1 *) pst)->tag |= temp;
2015  nlgetc(sfd); /* close '>' */
2016  ((PST1 *) pst)->macfeature = true;
2017  } else
2018  ungetc(ch,sfd);
2019  if ( type==pst_lcaret ) {
2020  /* These are meaningless for lcarets, set them to innocuous values */
2021  ((PST1 *) pst)->script_lang_index = SLI_UNKNOWN;
2022  ((PST1 *) pst)->tag = CHR(' ',' ',' ',' ');
2023  } else if ( ((PST1 *) pst)->script_lang_index>=((SplineFont1 *) sli_sf)->sli_cnt && ((PST1 *) pst)->script_lang_index!=SLI_NESTED ) {
2024  static int complained=false;
2025  if ( !complained )
2026  IError("'%c%c%c%c' in %s has a script index out of bounds: %d",
2027  (((PST1 *) pst)->tag>>24), (((PST1 *) pst)->tag>>16)&0xff, (((PST1 *) pst)->tag>>8)&0xff, ((PST1 *) pst)->tag&0xff,
2028  sc->name, ((PST1 *) pst)->script_lang_index );
2029  else
2030  IError( "'%c%c%c%c' in %s has a script index out of bounds: %d\n",
2031  (((PST1 *) pst)->tag>>24), (((PST1 *) pst)->tag>>16)&0xff, (((PST1 *) pst)->tag>>8)&0xff, ((PST1 *) pst)->tag&0xff,
2032  sc->name, ((PST1 *) pst)->script_lang_index );
2033  ((PST1 *) pst)->script_lang_index = SFFindBiggestScriptLangIndex(sli_sf,
2035  complained = true;
2036  }
2037  }
2038  if ( (sf->sfd_version<2)!=old ) {
2039  IError( "Version mixup in PST of sfd file." );
2040 exit(1);
2041  }
2042  if ( last==NULL )
2043  sc->possub = pst;
2044  else
2045  last->next = pst;
2046  last = pst;
2047  pst->type = type;
2048  if ( pst->type==pst_position ) {
2049  fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
2050  &pst->u.pos.xoff, &pst->u.pos.yoff,
2051  &pst->u.pos.h_adv_off, &pst->u.pos.v_adv_off);
2052  pst->u.pos.adjust = SFDReadValDevTab(sfd);
2053  ch = nlgetc(sfd); /* Eat new line */
2054  } else if ( pst->type==pst_pair ) {
2055  getname(sfd,tok);
2056  pst->u.pair.paired = copy(tok);
2057  pst->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
2058  fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
2059  &pst->u.pair.vr[0].xoff, &pst->u.pair.vr[0].yoff,
2060  &pst->u.pair.vr[0].h_adv_off, &pst->u.pair.vr[0].v_adv_off);
2061  pst->u.pair.vr[0].adjust = SFDReadValDevTab(sfd);
2062  fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
2063  &pst->u.pair.vr[1].xoff, &pst->u.pair.vr[1].yoff,
2064  &pst->u.pair.vr[1].h_adv_off, &pst->u.pair.vr[1].v_adv_off);
2065  pst->u.pair.vr[0].adjust = SFDReadValDevTab(sfd);
2066  ch = nlgetc(sfd);
2067  } else if ( pst->type==pst_lcaret ) {
2068  int i;
2069  fscanf( sfd, " %d", &pst->u.lcaret.cnt );
2070  pst->u.lcaret.carets = malloc(pst->u.lcaret.cnt*sizeof(int16));
2071  for ( i=0; i<pst->u.lcaret.cnt; ++i )
2072  fscanf( sfd, " %hd", &pst->u.lcaret.carets[i]);
2073  geteol(sfd,tok);
2074  } else {
2075  geteol(sfd,tok);
2076  pst->u.lig.components = copy(tok); /* it's in the same place for all formats */
2077  if ( isliga ) {
2078  pst->u.lig.lig = sc;
2079  if ( old )
2081  }
2082  }
2083 #ifdef FONTFORGE_CONFIG_CVT_OLD_MAC_FEATURES
2084  if ( old )
2085  CvtOldMacFeature((PST1 *) pst);
2086 #endif
2087  } else if ( strmatch(tok,"Colour:")==0 ) {
2088  uint32 temp;
2089  gethex(sfd,&temp);
2090  sc->color = temp;
2091  } else if ( strmatch(tok,"Comment:")==0 ) {
2092  sc->comment = SFDReadUTF7Str(sfd);
2093  } else if ( strmatch(tok,"TileMargin:")==0 ) {
2094  getreal(sfd,&sc->tile_margin);
2095  } else if ( strmatch(tok,"TileBounds:")==0 ) {
2096  getreal(sfd,&sc->tile_bounds.minx);
2097  getreal(sfd,&sc->tile_bounds.miny);
2098  getreal(sfd,&sc->tile_bounds.maxx);
2099  getreal(sfd,&sc->tile_bounds.maxy);
2100  } else if ( strmatch(tok,"EndChar")==0 ) {
2101  if ( sc->orig_pos<sf->glyphcnt )
2102  sf->glyphs[sc->orig_pos] = sc;
2103  /* Recalculating hint active zones may be needed for old .sfd files. */
2104  /* Do this when we have finished with other glyph components, */
2105  /* so that splines are already available */
2106  if ( had_old_dstems && sc->layers[ly_fore].splines != NULL )
2107  SCGuessHintInstancesList( sc,ly_fore,NULL,NULL,sc->dstem,false,true );
2108  if ( sc->layers[ly_fore].order2 )
2110 return( sc );
2111  } else {
2112  geteol(sfd,tok);
2113  }
2114  }
2115 }
2116 
2118  RefChar *rf;
2119  int ly;
2120 
2121  if ( sc->parent->multilayer ) {
2122  for ( ly=ly_fore; ly<ref->sc->layer_cnt; ++ly ) {
2123  for ( rf = ref->sc->layers[ly].refs; rf!=NULL; rf=rf->next ) {
2124  if ( rf->sc==sc ) { /* Huh? */
2125  ref->sc->layers[ly].refs = NULL;
2126  break;
2127  }
2128  if ( rf->layers[0].splines==NULL )
2129  SFDFixupRef(ref->sc,rf,layer);
2130  }
2131  }
2132  } else {
2133  for ( rf = ref->sc->layers[layer].refs; rf!=NULL; rf=rf->next ) {
2134  if ( rf->sc==sc ) { /* Huh? */
2135  ref->sc->layers[layer].refs = NULL;
2136  break;
2137  }
2138  if ( rf->layers[0].splines==NULL )
2139  SFDFixupRef(ref->sc,rf,layer);
2140  }
2141  }
2143  SCMakeDependent(sc,ref->sc);
2144 }
2145 
2146 /* Look for character duplicates, such as might be generated by having the same */
2147 /* glyph at two encoding slots */
2148 /* This is an obsolete convention, supported now only in sfd files */
2149 /* I think it is ok if something depends on this character, because the */
2150 /* code that handles references will automatically unwrap it down to be base */
2152  SplineChar *matched = sc;
2153 
2154  if ( sc==NULL || sc->parent==NULL || sc->parent->cidmaster!=NULL )
2155 return( sc ); /* Can't do this in CID keyed fonts */
2156 
2157  if ( sc->layer_cnt!=2 )
2158 return( sc );
2159 
2160  while ( sc->layers[ly_fore].refs!=NULL &&
2161  sc->layers[ly_fore].refs->sc!=NULL && /* Can happen if we are called during font loading before references are fixed up */
2162  sc->layers[ly_fore].refs->next==NULL &&
2163  sc->layers[ly_fore].refs->transform[0]==1 && sc->layers[ly_fore].refs->transform[1]==0 &&
2164  sc->layers[ly_fore].refs->transform[2]==0 && sc->layers[ly_fore].refs->transform[3]==1 &&
2165  sc->layers[ly_fore].refs->transform[4]==0 && sc->layers[ly_fore].refs->transform[5]==0 ) {
2166  char *basename = sc->layers[ly_fore].refs->sc->name;
2167  if ( strcmp(sc->name,basename)!=0 )
2168  break;
2169  matched = sc->layers[ly_fore].refs->sc;
2170  sc = sc->layers[ly_fore].refs->sc;
2171  }
2172 return( matched );
2173 }
2174 
2175 
2177  int i, isv;
2178  RefChar *refs, *rnext, *rprev;
2179  /*int isautorecovery = sf->changed;*/
2180  KernPair *kp, *prev, *next;
2181  EncMap *map = sf->map;
2182  int layer;
2183  int k,l;
2184  SplineFont *cidmaster = sf, *ksf;
2185 
2186  k = 1;
2187  if ( sf->subfontcnt!=0 )
2188  sf = sf->subfonts[0];
2189 
2190  ff_progress_change_line2(_("Interpreting Glyphs"));
2191  for (;;) {
2192  for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2193  SplineChar *sc = sf->glyphs[i];
2194  /* A changed character is one that has just been recovered */
2195  /* unchanged characters will already have been fixed up */
2196  /* Er... maybe not. If the character being recovered is refered to */
2197  /* by another character then we need to fix up that other char too*/
2198  /*if ( isautorecovery && !sc->changed )*/
2199  /*continue;*/
2200  for ( layer = 0; layer<sc->layer_cnt; ++layer ) {
2201  rprev = NULL;
2202  for ( refs = sc->layers[layer].refs; refs!=NULL; refs=rnext ) {
2203  rnext = refs->next;
2204  if ( refs->encoded ) { /* Old sfd format */
2205  if ( refs->orig_pos<map->encmax && map->map[refs->orig_pos]!=-1 )
2206  refs->orig_pos = map->map[refs->orig_pos];
2207  else
2208  refs->orig_pos = sf->glyphcnt;
2209  refs->encoded = false;
2210  }
2211  if ( refs->orig_pos<sf->glyphcnt && refs->orig_pos>=0 )
2212  refs->sc = sf->glyphs[refs->orig_pos];
2213  if ( refs->sc!=NULL ) {
2214  refs->unicode_enc = refs->sc->unicodeenc;
2215  refs->adobe_enc = getAdobeEnc(refs->sc->name);
2216  rprev = refs;
2217  if ( refs->use_my_metrics ) {
2218  if ( sc->width != refs->sc->width ) {
2219  LogError(_("Bad sfd file. Glyph %s has width %d even though it should be\n bound to the width of %s which is %d.\n"),
2220  sc->name, sc->width, refs->sc->name, refs->sc->width );
2221  sc->width = refs->sc->width;
2222  }
2223  }
2224  } else {
2225  RefCharFree(refs);
2226  if ( rprev!=NULL )
2227  rprev->next = rnext;
2228  else
2229  sc->layers[layer].refs = rnext;
2230  }
2231  }
2232  }
2233  /* In old sfd files we used a peculiar idiom to represent a multiply */
2234  /* encoded glyph. Fix it up now. Remove the fake glyph and adjust the*/
2235  /* map */
2236  /*if ( isautorecovery && !sc->changed )*/
2237  /*continue;*/
2238  for ( isv=0; isv<2; ++isv ) {
2239  for ( prev = NULL, kp=isv?sc->vkerns : sc->kerns; kp!=NULL; kp=next ) {
2240  int index = (intpt) (kp->sc);
2241 
2242  next = kp->next;
2243  // be impotent if the reference is already to the correct location
2244  if ( !kp->kcid ) { /* It's encoded (old sfds), else orig */
2245  if ( index>=map->encmax || map->map[index]==-1 )
2246  index = sf->glyphcnt;
2247  else
2248  index = map->map[index];
2249  }
2250  kp->kcid = false;
2251  ksf = sf;
2252  if ( cidmaster!=sf ) {
2253  for ( l=0; l<cidmaster->subfontcnt; ++l ) {
2254  ksf = cidmaster->subfonts[l];
2255  if ( index<ksf->glyphcnt && ksf->glyphs[index]!=NULL )
2256  break;
2257  }
2258  }
2259  if ( index>=ksf->glyphcnt || ksf->glyphs[index]==NULL ) {
2260  IError( "Bad kerning information in glyph %s\n", sc->name );
2261  kp->sc = NULL;
2262  } else {
2263  kp->sc = ksf->glyphs[index];
2264  }
2265 
2266  if ( kp->sc!=NULL )
2267  prev = kp;
2268  else{
2269  if ( prev!=NULL )
2270  prev->next = next;
2271  else if ( isv )
2272  sc->vkerns = next;
2273  else
2274  sc->kerns = next;
2275  chunkfree(kp,sizeof(KernPair));
2276  }
2277  }
2278  }
2279  if ( SCDuplicate(sc)!=sc ) {
2281  int orig = sc->orig_pos, enc = sf->map->backmap[orig], uni = sc->unicodeenc;
2282  SplineCharFree(sc);
2283  sf->glyphs[i]=NULL;
2284  sf->map->backmap[orig] = -1;
2285  sf->map->map[enc] = base->orig_pos;
2286  AltUniAdd(base,uni);
2287  }
2288  }
2289  for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2290  SplineChar *sc = sf->glyphs[i];
2291  for ( layer=0; layer<sc->layer_cnt; ++layer ) {
2292  for ( refs = sf->glyphs[i]->layers[layer].refs; refs!=NULL; refs=refs->next ) {
2293  SFDFixupRef(sf->glyphs[i],refs,layer);
2294  }
2295  }
2296  ff_progress_next();
2297  }
2298  if ( sf->cidmaster==NULL )
2299  for ( i=sf->glyphcnt-1; i>=0 && sf->glyphs[i]==NULL; --i )
2300  sf->glyphcnt = i;
2301  if ( k>=cidmaster->subfontcnt )
2302  break;
2303  sf = cidmaster->subfonts[k++];
2304  }
2305 }
2306 
2307 static void SFDGetPrivate(FILE *sfd,SplineFont *sf) {
2308  int i, cnt, len;
2309  char name[200];
2310  char *pt, *end;
2311 
2312  sf->private = calloc(1,sizeof(struct psdict));
2313  getint(sfd,&cnt);
2314  sf->private->next = sf->private->cnt = cnt;
2315  sf->private->values = calloc(cnt,sizeof(char *));
2316  sf->private->keys = calloc(cnt,sizeof(char *));
2317  for ( i=0; i<cnt; ++i ) {
2318  getname(sfd,name);
2319  sf->private->keys[i] = copy(name);
2320  getint(sfd,&len);
2321  nlgetc(sfd); /* skip space */
2322  pt = sf->private->values[i] = malloc(len+1);
2323  for ( end = pt+len; pt<end; ++pt )
2324  *pt = nlgetc(sfd);
2325  *pt='\0';
2326  }
2327 }
2328 
2329 static void SFDGetSubrs(FILE *sfd) {
2330  /* Obselete, parse it in case there are any old sfds */
2331  int i, cnt, tot, len;
2332  struct enc85 dec;
2333 
2334  getint(sfd,&cnt);
2335  tot = 0;
2336  for ( i=0; i<cnt; ++i ) {
2337  getint(sfd,&len);
2338  tot += len;
2339  }
2340 
2341  memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
2342  dec.sfd = sfd;
2343  for ( i=0; i<tot; ++i )
2344  Dec85(&dec);
2345 }
2346 
2347 static struct ttflangname *SFDGetLangName(FILE *sfd,struct ttflangname *old) {
2348  struct ttflangname *cur = chunkalloc(sizeof(struct ttflangname)), *prev;
2349  int i;
2350 
2351  getint(sfd,&cur->lang);
2352  for ( i=0; i<ttf_namemax; ++i )
2353  cur->names[i] = SFDReadUTF7Str(sfd);
2354  if ( old==NULL )
2355 return( cur );
2356  for ( prev = old; prev->next !=NULL; prev = prev->next );
2357  prev->next = cur;
2358 return( old );
2359 }
2360 
2361 static void SFDGetGasp(FILE *sfd,SplineFont *sf) {
2362  int i;
2363 
2364  getsint(sfd,(int16 *) &sf->gasp_cnt);
2365  sf->gasp = malloc(sf->gasp_cnt*sizeof(struct gasp));
2366  for ( i=0; i<sf->gasp_cnt; ++i ) {
2367  getsint(sfd,(int16 *) &sf->gasp[i].ppem);
2368  getsint(sfd,(int16 *) &sf->gasp[i].flags);
2369  }
2370  getsint(sfd,(int16 *) &sf->gasp_version);
2371 }
2372 
2373 static void SFDGetDesignSize(FILE *sfd,SplineFont *sf) {
2374  int ch;
2375  struct otfname *cur;
2376 
2377  getsint(sfd,(int16 *) &sf->design_size);
2378  while ( (ch=nlgetc(sfd))==' ' );
2379  ungetc(ch,sfd);
2380  if ( isdigit(ch)) {
2381  getsint(sfd,(int16 *) &sf->design_range_bottom);
2382  while ( (ch=nlgetc(sfd))==' ' );
2383  if ( ch!='-' )
2384  ungetc(ch,sfd);
2385  getsint(sfd,(int16 *) &sf->design_range_top);
2386  getsint(sfd,(int16 *) &sf->fontstyle_id);
2387  for (;;) {
2388  while ( (ch=nlgetc(sfd))==' ' );
2389  ungetc(ch,sfd);
2390  if ( !isdigit(ch))
2391  break;
2392  cur = chunkalloc(sizeof(struct otfname));
2393  cur->next = sf->fontstyle_name;
2394  sf->fontstyle_name = cur;
2395  getsint(sfd,(int16 *) &cur->lang);
2396  cur->name = SFDReadUTF7Str(sfd);
2397  }
2398  }
2399 }
2400 
2401 static void SFDGetOtfFeatName(FILE *sfd,SplineFont *sf) {
2402  int ch;
2403  struct otfname *cur;
2404  struct otffeatname *fn;
2405 
2406  fn = chunkalloc(sizeof(struct otffeatname));
2407  fn->tag = gettag(sfd);
2408  for (;;) {
2409  while ( (ch=nlgetc(sfd))==' ' );
2410  ungetc(ch,sfd);
2411  if ( !isdigit(ch))
2412  break;
2413  cur = chunkalloc(sizeof(struct otfname));
2414  cur->next = fn->names;
2415  fn->names = cur;
2416  getsint(sfd,(int16 *) &cur->lang);
2417  cur->name = SFDReadUTF7Str(sfd);
2418  }
2419  fn->next = sf->feat_names;
2420  sf->feat_names = fn;
2421 }
2422 
2423 static Encoding *SFDGetEncoding(FILE *sfd, char *tok) {
2424  Encoding *enc = NULL;
2425  int encname;
2426 
2427  if ( getint(sfd,&encname) ) {
2428  if ( encname<(int)(sizeof(charset_names)/sizeof(charset_names[0])-1) )
2429  enc = FindOrMakeEncoding(charset_names[encname]);
2430  } else {
2431  geteol(sfd,tok);
2433  }
2434  if ( enc==NULL )
2435  enc = &custom;
2436 return( enc );
2437 }
2438 
2439 static enum uni_interp SFDGetUniInterp(FILE *sfd, char *tok, SplineFont *sf) {
2440  int uniinterp = ui_none;
2441  int i;
2442 
2443  geteol(sfd,tok);
2444  for ( i=0; unicode_interp_names[i]!=NULL; ++i )
2445  if ( strcmp(tok,unicode_interp_names[i])==0 ) {
2446  uniinterp = i;
2447  break;
2448  }
2449  /* These values are now handled by namelists */
2450  if ( uniinterp == ui_adobe ) {
2451  sf->for_new_glyphs = NameListByName("AGL with PUA");
2452  uniinterp = ui_none;
2453  } else if ( uniinterp == ui_greek ) {
2454  sf->for_new_glyphs = NameListByName("Greek small caps");
2455  uniinterp = ui_none;
2456  } else if ( uniinterp == ui_ams ) {
2457  sf->for_new_glyphs = NameListByName("AMS Names");
2458  uniinterp = ui_none;
2459  }
2460 
2461 return( uniinterp );
2462 }
2463 
2464 static void SFDGetNameList(FILE *sfd, char *tok, SplineFont *sf) {
2465  NameList *nl;
2466 
2467  geteol(sfd,tok);
2468  nl = NameListByName(tok);
2469  if ( nl==NULL )
2470  LogError(_("Failed to find NameList: %s"), tok);
2471  else
2472  sf->for_new_glyphs = nl;
2473 }
2474 
2475 
2477  uint32 tag;
2478  int ch, isgpos;
2479  OTLookup *otl;
2480  char *name;
2481 
2482  while ( (ch=nlgetc(sfd))==' ' );
2483  if ( ch=='~' )
2484 return( NULL );
2485  else if ( old ) {
2486  if ( ch!='\'' )
2487 return( NULL );
2488 
2489  ungetc(ch,sfd);
2490  tag = gettag(sfd);
2491 return( (OTLookup *) (intpt) tag );
2492  } else {
2493  ungetc(ch,sfd);
2494  name = SFDReadUTF7Str(sfd);
2495  if ( name==NULL )
2496 return( NULL );
2497  for ( isgpos=0; isgpos<2; ++isgpos ) {
2498  for ( otl=isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl=otl->next ) {
2499  if ( strcmp(name,otl->lookup_name )==0 )
2500  goto break2;
2501  }
2502  }
2503  break2:
2504  free(name);
2505 return( otl );
2506  }
2507 }
2508 
2509 static void SFDParseChainContext(FILE *sfd,SplineFont *sf,FPST *fpst, char *tok, int old) {
2510  int ch, i, j, k, temp;
2511  SplineFont *sli_sf = sf->cidmaster ? sf->cidmaster : sf;
2512 
2513  fpst->type = strnmatch(tok,"ContextPos",10)==0 ? pst_contextpos :
2514  strnmatch(tok,"ContextSub",10)==0 ? pst_contextsub :
2515  strnmatch(tok,"ChainPos",8)==0 ? pst_chainpos :
2516  strnmatch(tok,"ChainSub",8)==0 ? pst_chainsub : pst_reversesub;
2517  getname(sfd,tok);
2518  fpst->format = strmatch(tok,"glyph")==0 ? pst_glyphs :
2519  strmatch(tok,"class")==0 ? pst_class :
2520  strmatch(tok,"coverage")==0 ? pst_coverage : pst_reversecoverage;
2521  if ( old ) {
2522  fscanf(sfd, "%hu %hu", &((FPST1 *) fpst)->flags, &((FPST1 *) fpst)->script_lang_index );
2523  if ( ((FPST1 *) fpst)->script_lang_index>=((SplineFont1 *) sli_sf)->sli_cnt && ((FPST1 *) fpst)->script_lang_index!=SLI_NESTED ) {
2524  static int complained=false;
2525  if ( ((SplineFont1 *) sli_sf)->sli_cnt==0 )
2526  IError("'%c%c%c%c' has a script index out of bounds: %d\nYou MUST fix this manually",
2527  (((FPST1 *) fpst)->tag>>24), (((FPST1 *) fpst)->tag>>16)&0xff, (((FPST1 *) fpst)->tag>>8)&0xff, ((FPST1 *) fpst)->tag&0xff,
2528  ((FPST1 *) fpst)->script_lang_index );
2529  else if ( !complained )
2530  IError("'%c%c%c%c' has a script index out of bounds: %d",
2531  (((FPST1 *) fpst)->tag>>24), (((FPST1 *) fpst)->tag>>16)&0xff, (((FPST1 *) fpst)->tag>>8)&0xff, ((FPST1 *) fpst)->tag&0xff,
2532  ((FPST1 *) fpst)->script_lang_index );
2533  else
2534  IError("'%c%c%c%c' has a script index out of bounds: %d\n",
2535  (((FPST1 *) fpst)->tag>>24), (((FPST1 *) fpst)->tag>>16)&0xff, (((FPST1 *) fpst)->tag>>8)&0xff, ((FPST1 *) fpst)->tag&0xff,
2536  ((FPST1 *) fpst)->script_lang_index );
2537  if ( ((SplineFont1 *) sli_sf)->sli_cnt!=0 )
2538  ((FPST1 *) fpst)->script_lang_index = ((SplineFont1 *) sli_sf)->sli_cnt-1;
2539  complained = true;
2540  }
2541  while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
2542  if ( ch=='\'' ) {
2543  ungetc(ch,sfd);
2544  ((FPST1 *) fpst)->tag = gettag(sfd);
2545  } else
2546  ungetc(ch,sfd);
2547  } else {
2549  if ( !fpst->subtable )
2550  LogError(_("Missing Subtable definition found in chained context"));
2551  else
2552  fpst->subtable->fpst = fpst;
2553  }
2554  fscanf(sfd, "%hu %hu %hu %hu", &fpst->nccnt, &fpst->bccnt, &fpst->fccnt, &fpst->rule_cnt );
2555  if ( fpst->nccnt!=0 || fpst->bccnt!=0 || fpst->fccnt!=0 ) {
2556  fpst->nclass = malloc(fpst->nccnt*sizeof(char *));
2557  fpst->nclassnames = calloc(fpst->nccnt,sizeof(char *));
2558  if ( fpst->nccnt!=0 ) fpst->nclass[0] = NULL;
2559  if ( fpst->bccnt!=0 || fpst->fccnt!=0 ) {
2560  fpst->bclass = malloc(fpst->bccnt*sizeof(char *));
2561  fpst->bclassnames = calloc(fpst->bccnt,sizeof(char *));
2562  if (fpst->bccnt!=0 ) fpst->bclass[0] = NULL;
2563  fpst->fclass = malloc(fpst->fccnt*sizeof(char *));
2564  fpst->fclassnames = calloc(fpst->fccnt,sizeof(char *));
2565  if (fpst->fccnt!=0 ) fpst->fclass[0] = NULL;
2566  }
2567  }
2568 
2569  for ( j=0; j<3; ++j ) {
2570  for ( i=1; i<(&fpst->nccnt)[j]; ++i ) {
2571  getname(sfd,tok);
2572  if ( i==1 && j==0 && strcmp(tok,"Class0:")==0 )
2573  i=0;
2574  getint(sfd,&temp);
2575  (&fpst->nclass)[j][i] = malloc(temp+1); (&fpst->nclass)[j][i][temp] = '\0';
2576  nlgetc(sfd); /* skip space */
2577  fread((&fpst->nclass)[j][i],1,temp,sfd);
2578  }
2579  }
2580 
2581  fpst->rules = calloc(fpst->rule_cnt,sizeof(struct fpst_rule));
2582  for ( i=0; i<fpst->rule_cnt; ++i ) {
2583  switch ( fpst->format ) {
2584  case pst_glyphs:
2585  for ( j=0; j<3; ++j ) {
2586  getname(sfd,tok);
2587  getint(sfd,&temp);
2588  (&fpst->rules[i].u.glyph.names)[j] = malloc(temp+1);
2589  (&fpst->rules[i].u.glyph.names)[j][temp] = '\0';
2590  nlgetc(sfd); /* skip space */
2591  fread((&fpst->rules[i].u.glyph.names)[j],1,temp,sfd);
2592  }
2593  break;
2594  case pst_class:
2595  fscanf( sfd, "%d %d %d", &fpst->rules[i].u.class.ncnt, &fpst->rules[i].u.class.bcnt, &fpst->rules[i].u.class.fcnt );
2596  for ( j=0; j<3; ++j ) {
2597  getname(sfd,tok);
2598  (&fpst->rules[i].u.class.nclasses)[j] = malloc((&fpst->rules[i].u.class.ncnt)[j]*sizeof(uint16));
2599  for ( k=0; k<(&fpst->rules[i].u.class.ncnt)[j]; ++k ) {
2600  getusint(sfd,&(&fpst->rules[i].u.class.nclasses)[j][k]);
2601  }
2602  }
2603  break;
2604  case pst_coverage:
2605  case pst_reversecoverage:
2606  fscanf( sfd, "%d %d %d", &fpst->rules[i].u.coverage.ncnt, &fpst->rules[i].u.coverage.bcnt, &fpst->rules[i].u.coverage.fcnt );
2607  for ( j=0; j<3; ++j ) {
2608  (&fpst->rules[i].u.coverage.ncovers)[j] = malloc((&fpst->rules[i].u.coverage.ncnt)[j]*sizeof(char *));
2609  for ( k=0; k<(&fpst->rules[i].u.coverage.ncnt)[j]; ++k ) {
2610  getname(sfd,tok);
2611  getint(sfd,&temp);
2612  (&fpst->rules[i].u.coverage.ncovers)[j][k] = malloc(temp+1);
2613  (&fpst->rules[i].u.coverage.ncovers)[j][k][temp] = '\0';
2614  nlgetc(sfd); /* skip space */
2615  fread((&fpst->rules[i].u.coverage.ncovers)[j][k],1,temp,sfd);
2616  }
2617  }
2618  break;
2619  default:
2620  break;
2621  }
2622  switch ( fpst->format ) {
2623  case pst_glyphs:
2624  case pst_class:
2625  case pst_coverage:
2626  getint(sfd,&fpst->rules[i].lookup_cnt);
2627  fpst->rules[i].lookups = malloc(fpst->rules[i].lookup_cnt*sizeof(struct seqlookup));
2628  for ( j=k=0; j<fpst->rules[i].lookup_cnt; ++j ) {
2629  getname(sfd,tok);
2630  getint(sfd,&fpst->rules[i].lookups[j].seq);
2631  fpst->rules[i].lookups[k].lookup = SFD_ParseNestedLookup(sfd,sf,old);
2632  if ( fpst->rules[i].lookups[k].lookup!=NULL )
2633  ++k;
2634  }
2635  fpst->rules[i].lookup_cnt = k;
2636  break;
2637  case pst_reversecoverage:
2638  getname(sfd,tok);
2639  getint(sfd,&temp);
2640  fpst->rules[i].u.rcoverage.replacements = malloc(temp+1);
2641  fpst->rules[i].u.rcoverage.replacements[temp] = '\0';
2642  nlgetc(sfd); /* skip space */
2643  fread(fpst->rules[i].u.rcoverage.replacements,1,temp,sfd);
2644  break;
2645  default:
2646  break;
2647  }
2648  }
2649  getname(sfd,tok); /* EndFPST, or one of the ClassName tokens (in newer sfds) */
2650  while ( strcmp(tok,"ClassNames:")==0 || strcmp(tok,"BClassNames:")==0 ||
2651  strcmp(tok,"FClassNames:")==0 ) {
2652  int which = strcmp(tok,"ClassNames:")==0 ? 0 :
2653  strcmp(tok,"BClassNames:")==0 ? 1 : 2;
2654  int cnt = (&fpst->nccnt)[which];
2655  char **classnames = (&fpst->nclassnames)[which];
2656  int i;
2657 
2658  for ( i=0; i<cnt; ++i )
2659  classnames[i] = SFDReadUTF7Str(sfd);
2660  getname(sfd,tok); /* EndFPST, or one of the ClassName tokens (in newer sfds) */
2661  }
2662 
2663 }
2664 
2665 static void SFDParseStateMachine(FILE *sfd,SplineFont *sf,ASM *sm, char *tok,int old) {
2666  int i, temp;
2667 
2668  sm->type = strnmatch(tok,"MacIndic",8)==0 ? asm_indic :
2669  strnmatch(tok,"MacContext",10)==0 ? asm_context :
2670  strnmatch(tok,"MacLigature",11)==0 ? asm_lig :
2671  strnmatch(tok,"MacSimple",9)==0 ? asm_simple :
2672  strnmatch(tok,"MacKern",7)==0 ? asm_kern : asm_insert;
2673  if ( old ) {
2674  getusint(sfd,&((ASM1 *) sm)->feature);
2675  nlgetc(sfd); /* Skip comma */
2676  getusint(sfd,&((ASM1 *) sm)->setting);
2677  } else {
2679  sm->subtable->sm = sm;
2680  }
2681  getusint(sfd,&sm->flags);
2682  getusint(sfd,&sm->class_cnt);
2683  getusint(sfd,&sm->state_cnt);
2684 
2685  sm->classes = malloc(sm->class_cnt*sizeof(char *));
2686  sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
2687  for ( i=4; i<sm->class_cnt; ++i ) {
2688  getname(sfd,tok);
2689  getint(sfd,&temp);
2690  sm->classes[i] = malloc(temp+1); sm->classes[i][temp] = '\0';
2691  nlgetc(sfd); /* skip space */
2692  fread(sm->classes[i],1,temp,sfd);
2693  }
2694 
2695  sm->state = malloc(sm->class_cnt*sm->state_cnt*sizeof(struct asm_state));
2696  for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
2697  getusint(sfd,&sm->state[i].next_state);
2698  getusint(sfd,&sm->state[i].flags);
2699  if ( sm->type == asm_context ) {
2702  } else if ( sm->type == asm_insert ) {
2703  getint(sfd,&temp);
2704  if ( temp==0 )
2705  sm->state[i].u.insert.mark_ins = NULL;
2706  else {
2707  sm->state[i].u.insert.mark_ins = malloc(temp+1); sm->state[i].u.insert.mark_ins[temp] = '\0';
2708  nlgetc(sfd); /* skip space */
2709  fread(sm->state[i].u.insert.mark_ins,1,temp,sfd);
2710  }
2711  getint(sfd,&temp);
2712  if ( temp==0 )
2713  sm->state[i].u.insert.cur_ins = NULL;
2714  else {
2715  sm->state[i].u.insert.cur_ins = malloc(temp+1); sm->state[i].u.insert.cur_ins[temp] = '\0';
2716  nlgetc(sfd); /* skip space */
2717  fread(sm->state[i].u.insert.cur_ins,1,temp,sfd);
2718  }
2719  } else if ( sm->type == asm_kern ) {
2720  int j;
2721  getint(sfd,&sm->state[i].u.kern.kcnt);
2722  if ( sm->state[i].u.kern.kcnt!=0 )
2723  sm->state[i].u.kern.kerns = malloc(sm->state[i].u.kern.kcnt*sizeof(int16));
2724  for ( j=0; j<sm->state[i].u.kern.kcnt; ++j ) {
2725  getint(sfd,&temp);
2726  sm->state[i].u.kern.kerns[j] = temp;
2727  }
2728  }
2729  }
2730  getname(sfd,tok); /* EndASM */
2731 }
2732 
2733 static struct macname *SFDParseMacNames(FILE *sfd, char *tok) {
2734  struct macname *head=NULL, *last=NULL, *cur;
2735  int enc, lang, len;
2736  char *pt;
2737  int ch;
2738 
2739  while ( strcmp(tok,"MacName:")==0 ) {
2740  cur = chunkalloc(sizeof(struct macname));
2741  if ( last==NULL )
2742  head = cur;
2743  else
2744  last->next = cur;
2745  last = cur;
2746 
2747  getint(sfd,&enc);
2748  getint(sfd,&lang);
2749  getint(sfd,&len);
2750  cur->enc = enc;
2751  cur->lang = lang;
2752  cur->name = pt = malloc(len+1);
2753 
2754  while ( (ch=nlgetc(sfd))==' ');
2755  if ( ch=='"' )
2756  ch = nlgetc(sfd);
2757  while ( ch!='"' && ch!=EOF && pt<cur->name+len ) {
2758  if ( ch=='\\' ) {
2759  *pt = (nlgetc(sfd)-'0')<<6;
2760  *pt |= (nlgetc(sfd)-'0')<<3;
2761  *pt |= (nlgetc(sfd)-'0');
2762  } else
2763  *pt++ = ch;
2764  ch = nlgetc(sfd);
2765  }
2766  *pt = '\0';
2767  getname(sfd,tok);
2768  }
2769 return( head );
2770 }
2771 
2773  MacFeat *cur, *head=NULL, *last=NULL;
2774  struct macsetting *slast, *scur;
2775  int feat, ism, def, set;
2776 
2777  while ( strcmp(tok,"MacFeat:")==0 ) {
2778  cur = chunkalloc(sizeof(MacFeat));
2779  if ( last==NULL )
2780  head = cur;
2781  else
2782  last->next = cur;
2783  last = cur;
2784 
2785  getint(sfd,&feat); getint(sfd,&ism); getint(sfd, &def);
2786  cur->feature = feat; cur->ismutex = ism; cur->default_setting = def;
2787  getname(sfd,tok);
2788  cur->featname = SFDParseMacNames(sfd,tok);
2789  slast = NULL;
2790  while ( strcmp(tok,"MacSetting:")==0 ) {
2791  scur = chunkalloc(sizeof(struct macsetting));
2792  if ( slast==NULL )
2793  cur->settings = scur;
2794  else
2795  slast->next = scur;
2796  slast = scur;
2797 
2798  getint(sfd,&set);
2799  scur->setting = set;
2800  getname(sfd,tok);
2801  scur->setname = SFDParseMacNames(sfd,tok);
2802  }
2803  }
2804 return( head );
2805 }
2806 
2807 static char *SFDParseMMSubroutine(FILE *sfd) {
2808  char buffer[400], *sofar=calloc(1,1);
2809  const char *endtok = "EndMMSubroutine";
2810  int len = 0, blen, first=true;
2811 
2812  while ( fgets(buffer,sizeof(buffer),sfd)!=NULL ) {
2813  if ( strncmp(buffer,endtok,strlen(endtok))==0 )
2814  break;
2815  if ( first ) {
2816  first = false;
2817  if ( strcmp(buffer,"\n")==0 )
2818  continue;
2819  }
2820  blen = strlen(buffer);
2821  sofar = realloc(sofar,len+blen+1);
2822  strcpy(sofar+len,buffer);
2823  len += blen;
2824  }
2825  if ( len>0 && sofar[len-1]=='\n' )
2826  sofar[len-1] = '\0';
2827 return( sofar );
2828 }
2829 
2830 static void MMInferStuff(MMSet *mm) {
2831  int i,j;
2832 
2833  if ( mm==NULL )
2834 return;
2835  if ( mm->apple ) {
2836  for ( i=0; i<mm->axis_count; ++i ) {
2837  for ( j=0; j<mm->axismaps[i].points; ++j ) {
2838  real val = mm->axismaps[i].blends[j];
2839  if ( val == -1. )
2840  mm->axismaps[i].min = mm->axismaps[i].designs[j];
2841  else if ( val==0 )
2842  mm->axismaps[i].def = mm->axismaps[i].designs[j];
2843  else if ( val==1 )
2844  mm->axismaps[i].max = mm->axismaps[i].designs[j];
2845  }
2846  }
2847  }
2848 }
2849 
2850 static void SFDSizeMap(EncMap *map,int glyphcnt,int enccnt) {
2851  if ( glyphcnt>map->backmax ) {
2852  map->backmap = realloc(map->backmap,glyphcnt*sizeof(int));
2853  memset(map->backmap+map->backmax,-1,(glyphcnt-map->backmax)*sizeof(int));
2854  map->backmax = glyphcnt;
2855  }
2856  if ( enccnt>map->encmax ) {
2857  map->map = realloc(map->map,enccnt*sizeof(int));
2858  memset(map->map+map->backmax,-1,(enccnt-map->encmax)*sizeof(int));
2859  map->encmax = map->enccount = enccnt;
2860  }
2861 }
2862 
2863 static SplineFont *SFD_GetFont(FILE *sfd,SplineFont *cidmaster,char *tok,
2864  int fromdir, char *dirname, float sfdversion);
2865 
2866 static void SFD_DoAltUnis(SplineFont *sf) {
2867  int i;
2868  struct altuni *alt;
2869  SplineChar *sc;
2870 
2871  for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
2872  for ( alt = sc->altuni; alt!=NULL; alt = alt->next ) {
2873  if ( alt->vs==-1 && alt->fid==0 ) {
2874  int enc = EncFromUni(alt->unienc,sf->map->enc);
2875  if ( enc!=-1 )
2876  SFDSetEncMap(sf,sc->orig_pos,enc);
2877  }
2878  }
2879  }
2880 }
2881 
2882 static void SFDParseLookup(FILE *sfd,OTLookup *otl) {
2883  int ch;
2884  struct lookup_subtable *sub, *lastsub;
2885  FeatureScriptLangList *fl, *lastfl;
2886  struct scriptlanglist *sl, *lastsl;
2887  int i, lcnt, lmax=0;
2888  uint32 *langs=NULL;
2889  char *subname;
2890 
2891  while ( (ch=nlgetc(sfd))==' ' );
2892  if ( ch=='{' ) {
2893  lastsub = NULL;
2894  while ( (subname = SFDReadUTF7Str(sfd))!=NULL ) {
2895  while ( (ch=nlgetc(sfd))==' ' );
2896  ungetc(ch,sfd);
2897  sub = chunkalloc(sizeof(struct lookup_subtable));
2898  sub->subtable_name = subname;
2899  sub->lookup = otl;
2900  switch ( otl->lookup_type ) {
2901  case gsub_single:
2902  while ( (ch=nlgetc(sfd))==' ' );
2903  if ( ch=='(' ) {
2904  sub->suffix = SFDReadUTF7Str(sfd);
2905  while ( (ch=nlgetc(sfd))==' ' );
2906  /* slurp final paren */
2907  } else
2908  ungetc(ch,sfd);
2909  sub->per_glyph_pst_or_kern = true;
2910  break;
2911  case gsub_multiple: case gsub_alternate: case gsub_ligature:
2912  case gpos_single:
2913  sub->per_glyph_pst_or_kern = true;
2914  break;
2915  case gpos_pair:
2916  if ( (ch=nlgetc(sfd))=='(' ) {
2917  ch = nlgetc(sfd);
2918  sub->vertical_kerning = (ch=='1');
2919  nlgetc(sfd); /* slurp final paren */
2920  ch=nlgetc(sfd);
2921  }
2922  if ( ch=='[' ) {
2923  getsint(sfd,&sub->separation);
2924  nlgetc(sfd); /* slurp comma */
2925  getsint(sfd,&sub->minkern);
2926  nlgetc(sfd); /* slurp comma */
2927  ch = nlgetc(sfd);
2928  sub->kerning_by_touch = ((ch-'0')&1)?1:0;
2929  sub->onlyCloser = ((ch-'0')&2)?1:0;
2930  sub->dontautokern = ((ch-'0')&4)?1:0;
2931  nlgetc(sfd); /* slurp final bracket */
2932  } else {
2933  ungetc(ch,sfd);
2934  }
2935  sub->per_glyph_pst_or_kern = true;
2936  break;
2938  sub->anchor_classes = true;
2939  break;
2940  default:
2941  break;
2942  }
2943  if ( lastsub==NULL )
2944  otl->subtables = sub;
2945  else
2946  lastsub->next = sub;
2947  lastsub = sub;
2948  }
2949  while ( (ch=nlgetc(sfd))==' ' );
2950  if ( ch=='}' )
2951  ch = nlgetc(sfd);
2952  }
2953  while ( ch==' ' )
2954  ch = nlgetc(sfd);
2955  if ( ch=='[' ) {
2956  lastfl = NULL;
2957  for (;;) {
2958  while ( (ch=nlgetc(sfd))==' ' );
2959  if ( ch==']' )
2960  break;
2961  fl = chunkalloc(sizeof(FeatureScriptLangList));
2962  if ( lastfl==NULL )
2963  otl->features = fl;
2964  else
2965  lastfl->next = fl;
2966  lastfl = fl;
2967  if ( ch=='<' ) {
2968  int ft=0,fs=0;
2969  fscanf(sfd,"%d,%d>", &ft, &fs );
2970  fl->ismac = true;
2971  fl->featuretag = (ft<<16) | fs;
2972  } else if ( ch=='\'' ) {
2973  ungetc(ch,sfd);
2974  fl->featuretag = gettag(sfd);
2975  }
2976  while ( (ch=nlgetc(sfd))==' ' );
2977  if ( ch=='(' ) {
2978  lastsl = NULL;
2979  for (;;) {
2980  while ( (ch=nlgetc(sfd))==' ' );
2981  if ( ch==')' )
2982  break;
2983  sl = chunkalloc(sizeof(struct scriptlanglist));
2984  if ( lastsl==NULL )
2985  fl->scripts = sl;
2986  else
2987  lastsl->next = sl;
2988  lastsl = sl;
2989  if ( ch=='\'' ) {
2990  ungetc(ch,sfd);
2991  sl->script = gettag(sfd);
2992  }
2993  while ( (ch=nlgetc(sfd))==' ' );
2994  if ( ch=='<' ) {
2995  lcnt = 0;
2996  for (;;) {
2997  while ( (ch=nlgetc(sfd))==' ' );
2998  if ( ch=='>' )
2999  break;
3000  if ( ch=='\'' ) {
3001  ungetc(ch,sfd);
3002  if ( lcnt>=lmax )
3003  langs = realloc(langs,(lmax+=10)*sizeof(uint32));
3004  langs[lcnt++] = gettag(sfd);
3005  }
3006  }
3007  sl->lang_cnt = lcnt;
3008  if ( lcnt>MAX_LANG )
3009  sl->morelangs = malloc((lcnt-MAX_LANG)*sizeof(uint32));
3010  for ( i=0; i<lcnt; ++i ) {
3011  if ( i<MAX_LANG )
3012  sl->langs[i] = langs[i];
3013  else
3014  sl->morelangs[i-MAX_LANG] = langs[i];
3015  }
3016  }
3017  }
3018  }
3019  }
3020  }
3021  free(langs);
3022 }
3023 
3024 static void SFDParseMathItem(FILE *sfd,SplineFont *sf,char *tok) {
3025  /* The first five characters of a math item's keyword will be "MATH:" */
3026  /* the rest will be one of the entries in math_constants_descriptor */
3027  int i;
3028  struct MATH *math;
3029 
3030  if ( (math = sf->MATH) == NULL )
3031  math = sf->MATH = calloc(1,sizeof(struct MATH));
3032  for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
3034  int len = strlen( name );
3035  if ( strncmp(tok+5,name,len)==0 && tok[5+len] == ':' && tok[6+len]=='\0' ) {
3036  int16 *pos = (int16 *) (((char *) (math)) + math_constants_descriptor[i].offset );
3037  getsint(sfd,pos);
3038  if ( math_constants_descriptor[i].devtab_offset != -1 ) {
3039  DeviceTable **devtab = (DeviceTable **) (((char *) (math)) + math_constants_descriptor[i].devtab_offset );
3040  *devtab = SFDReadDeviceTable(sfd,*devtab);
3041  break;
3042  }
3043  }
3044  }
3045 }
3046 
3047 static struct baselangextent *ParseBaseLang(FILE *sfd) {
3048  struct baselangextent *bl;
3049  struct baselangextent *cur, *last;
3050  int ch;
3051 
3052  while ( (ch=nlgetc(sfd))==' ' );
3053  if ( ch=='{' ) {
3054  bl = chunkalloc(sizeof(struct baselangextent));
3055  while ( (ch=nlgetc(sfd))==' ' );
3056  ungetc(ch,sfd);
3057  if ( ch=='\'' )
3058  bl->lang = gettag(sfd); /* Lang or Feature tag, or nothing */
3059  getsint(sfd,&bl->descent);
3060  getsint(sfd,&bl->ascent);
3061  last = NULL;
3062  while ( (ch=nlgetc(sfd))==' ' );
3063  while ( ch=='{' ) {
3064  ungetc(ch,sfd);
3065  cur = ParseBaseLang(sfd);
3066  if ( last==NULL )
3067  bl->features = cur;
3068  else
3069  last->next = cur;
3070  last = cur;
3071  while ( (ch=nlgetc(sfd))==' ' );
3072  }
3073  if ( ch!='}' ) ungetc(ch,sfd);
3074 return( bl );
3075  }
3076 return( NULL );
3077 }
3078 
3079 static struct basescript *SFDParseBaseScript(FILE *sfd,struct Base *base) {
3080  struct basescript *bs;
3081  int i, ch;
3082  struct baselangextent *last, *cur;
3083 
3084  if ( base==NULL )
3085 return(NULL);
3086 
3087  bs = chunkalloc(sizeof(struct basescript));
3088 
3089  bs->script = gettag(sfd);
3090  getint(sfd,&bs->def_baseline);
3091  if ( base->baseline_cnt!=0 ) {
3092  bs->baseline_pos = calloc(base->baseline_cnt,sizeof(int16));
3093  for ( i=0; i<base->baseline_cnt; ++i )
3094  getsint(sfd, &bs->baseline_pos[i]);
3095  }
3096  while ( (ch=nlgetc(sfd))==' ' );
3097  last = NULL;
3098  while ( ch=='{' ) {
3099  ungetc(ch,sfd);
3100  cur = ParseBaseLang(sfd);
3101  if ( last==NULL )
3102  bs->langs = cur;
3103  else
3104  last->next = cur;
3105  last = cur;
3106  while ( (ch=nlgetc(sfd))==' ' );
3107  }
3108 return( bs );
3109 }
3110 
3111 static struct Base *SFDParseBase(FILE *sfd) {
3112  struct Base *base = chunkalloc(sizeof(struct Base));
3113  int i;
3114 
3115  getint(sfd,&base->baseline_cnt);
3116  if ( base->baseline_cnt!=0 ) {
3117  base->baseline_tags = malloc(base->baseline_cnt*sizeof(uint32));
3118  for ( i=0; i<base->baseline_cnt; ++i )
3119  base->baseline_tags[i] = gettag(sfd);
3120  }
3121 return( base );
3122 }
3123 
3125  int ch;
3126  OTLookup *space[100], **buf=space, *otl, **ret;
3127  int lcnt=0, lmax=100;
3128  char *name;
3129 
3130  for (;;) {
3131  while ( (ch=nlgetc(sfd))==' ' );
3132  if ( ch=='\n' || ch==EOF )
3133  break;
3134  ungetc(ch,sfd);
3135  name = SFDReadUTF7Str(sfd);
3136  otl = SFFindLookup(sf,name);
3137  free(name);
3138  if ( otl!=NULL ) {
3139  if ( lcnt>lmax ) {
3140  if ( buf==space ) {
3141  buf = malloc((lmax=lcnt+50)*sizeof(OTLookup *));
3142  memcpy(buf,space,sizeof(space));
3143  } else
3144  buf = realloc(buf,(lmax+=50)*sizeof(OTLookup *));
3145  }
3146  buf[lcnt++] = otl;
3147  }
3148  }
3149  if ( lcnt==0 )
3150 return( NULL );
3151 
3152  ret = malloc((lcnt+1)*sizeof(OTLookup *));
3153  memcpy(ret,buf,lcnt*sizeof(OTLookup *));
3154  ret[lcnt] = NULL;
3155 return( ret );
3156 }
3157 
3158 static void SFDParseJustify(FILE *sfd, SplineFont *sf, char *tok) {
3159  Justify *last=NULL, *cur;
3160  struct jstf_lang *jlang, *llast;
3161  int p = 0,ch;
3162 
3163  while ( strcmp(tok,"Justify:")==0 ) {
3164  cur = chunkalloc(sizeof(Justify));
3165  if ( last==NULL )
3166  sf->justify = cur;
3167  else
3168  last->next = cur;
3169  last = cur;
3170  llast = jlang = NULL;
3171  cur->script = gettag(sfd);
3172  while ( getname(sfd,tok)>0 ) {
3173  if ( strcmp(tok,"Justify:")==0 || strcmp(tok,"EndJustify")==0 )
3174  break;
3175  if ( strcmp(tok,"JstfExtender:")==0 ) {
3176  while ( (ch=nlgetc(sfd))==' ' );
3177  ungetc(ch,sfd);
3178  geteol(sfd,tok);
3179  cur->extenders = copy(tok);
3180  } else if ( strcmp(tok,"JstfLang:")==0 ) {
3181  jlang = chunkalloc(sizeof(struct jstf_lang));
3182  if ( llast==NULL )
3183  cur->langs = jlang;
3184  else
3185  llast->next = jlang;
3186  llast = jlang;
3187  jlang->lang = gettag(sfd);
3188  p = -1;
3189  getint(sfd,&jlang->cnt);
3190  if ( jlang->cnt!=0 )
3191  jlang->prios = calloc(jlang->cnt,sizeof(struct jstf_prio));
3192  } else if ( strcmp(tok,"JstfPrio:")==0 ) {
3193  if ( jlang!=NULL ) {
3194  ++p;
3195  if ( p>= jlang->cnt ) {
3196  jlang->prios = realloc(jlang->prios,(p+1)*sizeof(struct jstf_prio));
3197  memset(jlang->prios+jlang->cnt,0,(p+1-jlang->cnt)*sizeof(struct jstf_prio));
3198  jlang->cnt = p+1;
3199  }
3200  }
3201  } else if ( strcmp(tok,"JstfEnableShrink:" )==0 ) {
3202  if ( p<0 ) p=0;
3203  if ( jlang!=NULL && p<jlang->cnt )
3204  jlang->prios[p].enableShrink = SFDLookupList(sfd,sf);
3205  } else if ( strcmp(tok,"JstfDisableShrink:" )==0 ) {
3206  if ( p<0 ) p=0;
3207  if ( jlang!=NULL && p<jlang->cnt )
3208  jlang->prios[p].disableShrink = SFDLookupList(sfd,sf);
3209  } else if ( strcmp(tok,"JstfMaxShrink:" )==0 ) {
3210  if ( p<0 ) p=0;
3211  if ( jlang!=NULL && p<jlang->cnt )
3212  jlang->prios[p].maxShrink = SFDLookupList(sfd,sf);
3213  } else if ( strcmp(tok,"JstfEnableExtend:" )==0 ) {
3214  if ( p<0 ) p=0;
3215  if ( jlang!=NULL && p<jlang->cnt )
3216  jlang->prios[p].enableExtend = SFDLookupList(sfd,sf);
3217  } else if ( strcmp(tok,"JstfDisableExtend:" )==0 ) {
3218  if ( p<0 ) p=0;
3219  if ( jlang!=NULL && p<jlang->cnt )
3220  jlang->prios[p].disableExtend = SFDLookupList(sfd,sf);
3221  } else if ( strcmp(tok,"JstfMaxExtend:" )==0 ) {
3222  if ( p<0 ) p=0;
3223  if ( jlang!=NULL && p<jlang->cnt )
3224  jlang->prios[p].maxExtend = SFDLookupList(sfd,sf);
3225  } else
3226  geteol(sfd,tok);
3227  }
3228  }
3229 }
3230 
3231 
3232 
3234 {
3235  memset( d, 0, sizeof(SFD_GetFontMetaDataData));
3236 }
3237 
3238 /**
3239  *
3240  * @return true if the function matched the current token. If true
3241  * is returned the caller should avoid further processing of 'tok'
3242  * a return of false means that the caller might try
3243  * to handle the token with another function or drop it.
3244  */
3246  char *tok,
3247  SplineFont *sf,
3249 {
3250  int ch;
3251  int i;
3252  KernClass* kc = 0;
3253  int old;
3254  char val[2000];
3255 
3256  // This allows us to assume we can dereference d
3257  // at all times
3258  static SFD_GetFontMetaDataData my_static_d;
3259  static int my_static_d_is_virgin = 1;
3260  if( !d )
3261  {
3262  if( my_static_d_is_virgin )
3263  {
3264  my_static_d_is_virgin = 0;
3265  SFD_GetFontMetaDataData_Init( &my_static_d );
3266  }
3267  d = &my_static_d;
3268  }
3269 
3270  if ( strmatch(tok,"FontName:")==0 )
3271  {
3272  geteol(sfd,val);
3273  sf->fontname = copy(val);
3274  }
3275  else if ( strmatch(tok,"FullName:")==0 )
3276  {
3277  geteol(sfd,val);
3278  sf->fullname = copy(val);
3279  }
3280  else if ( strmatch(tok,"FamilyName:")==0 )
3281  {
3282  geteol(sfd,val);
3283  sf->familyname = copy(val);
3284  }
3285  else if ( strmatch(tok,"DefaultBaseFilename:")==0 )
3286  {
3287  geteol(sfd,val);
3288  sf->defbasefilename = copy(val);
3289  }
3290  else if ( strmatch(tok,"Weight:")==0 )
3291  {
3292  getprotectedname(sfd,val);
3293  sf->weight = copy(val);
3294  }
3295  else if ( strmatch(tok,"Copyright:")==0 )
3296  {
3297  sf->copyright = getquotedeol(sfd);
3298  }
3299  else if ( strmatch(tok,"Comments:")==0 )
3300  {
3301  char *temp = getquotedeol(sfd);
3302  sf->comments = latin1_2_utf8_copy(temp);
3303  free(temp);
3304  }
3305  else if ( strmatch(tok,"UComments:")==0 )
3306  {
3307  sf->comments = SFDReadUTF7Str(sfd);
3308  }
3309  else if ( strmatch(tok,"FontLog:")==0 )
3310  {
3311  sf->fontlog = SFDReadUTF7Str(sfd);
3312  }
3313  else if ( strmatch(tok,"Version:")==0 )
3314  {
3315  geteol(sfd,val);
3316  sf->version = copy(val);
3317  }
3318  else if ( strmatch(tok,"StyleMapFamilyName:")==0 )
3319  {
3320  sf->styleMapFamilyName = SFDReadUTF7Str(sfd);
3321  }
3322  /* Legacy attribute for StyleMapFamilyName. Deprecated. */
3323  else if ( strmatch(tok,"OS2FamilyName:")==0 )
3324  {
3325  if (sf->styleMapFamilyName == NULL)
3326  sf->styleMapFamilyName = SFDReadUTF7Str(sfd);
3327  }
3328  else if ( strmatch(tok,"FONDName:")==0 )
3329  {
3330  geteol(sfd,val);
3331  sf->fondname = copy(val);
3332  }
3333  else if ( strmatch(tok,"ItalicAngle:")==0 )
3334  {
3335  getreal(sfd,&sf->italicangle);
3336  }
3337  else if ( strmatch(tok,"StrokeWidth:")==0 )
3338  {
3339  getreal(sfd,&sf->strokewidth);
3340  }
3341  else if ( strmatch(tok,"UnderlinePosition:")==0 )
3342  {
3343  getreal(sfd,&sf->upos);
3344  }
3345  else if ( strmatch(tok,"UnderlineWidth:")==0 )
3346  {
3347  getreal(sfd,&sf->uwidth);
3348  }
3349  else if ( strmatch(tok,"ModificationTime:")==0 )
3350  {
3351  getlonglong(sfd,&sf->modificationtime);
3352  }
3353  else if ( strmatch(tok,"CreationTime:")==0 )
3354  {
3355  getlonglong(sfd,&sf->creationtime);
3356  d->hadtimes = true;
3357  }
3358  else if ( strmatch(tok,"PfmFamily:")==0 )
3359  {
3360  int temp;
3361  getint(sfd,&temp);
3362  sf->pfminfo.pfmfamily = temp;
3363  sf->pfminfo.pfmset = true;
3364  }
3365  else if ( strmatch(tok,"LangName:")==0 )
3366  {
3367  sf->names = SFDGetLangName(sfd,sf->names);
3368  }
3369  else if ( strmatch(tok,"GaspTable:")==0 )
3370  {
3371  SFDGetGasp(sfd,sf);
3372  }
3373  else if ( strmatch(tok,"DesignSize:")==0 )
3374  {
3375  SFDGetDesignSize(sfd,sf);
3376  }
3377  else if ( strmatch(tok,"OtfFeatName:")==0 )
3378  {
3379  SFDGetOtfFeatName(sfd,sf);
3380  }
3381  else if ( strmatch(tok,"PfmWeight:")==0 || strmatch(tok,"TTFWeight:")==0 )
3382  {
3383  getsint(sfd,&sf->pfminfo.weight);
3384  sf->pfminfo.pfmset = true;
3385  }
3386  else if ( strmatch(tok,"TTFWidth:")==0 )
3387  {
3388  getsint(sfd,&sf->pfminfo.width);
3389  sf->pfminfo.pfmset = true;
3390  }
3391  else if ( strmatch(tok,"Panose:")==0 )
3392  {
3393  int temp,i;
3394  for ( i=0; i<10; ++i )
3395  {
3396  getint(sfd,&temp);
3397  sf->pfminfo.panose[i] = temp;
3398  }
3399  sf->pfminfo.panose_set = true;
3400  }
3401  else if ( strmatch(tok,"LineGap:")==0 )
3402  {
3403  getsint(sfd,&sf->pfminfo.linegap);
3404  sf->pfminfo.pfmset = true;
3405  }
3406  else if ( strmatch(tok,"VLineGap:")==0 )
3407  {
3408  getsint(sfd,&sf->pfminfo.vlinegap);
3409  sf->pfminfo.pfmset = true;
3410  }
3411  else if ( strmatch(tok,"HheadAscent:")==0 )
3412  {
3413  getsint(sfd,&sf->pfminfo.hhead_ascent);
3414  }
3415  else if ( strmatch(tok,"HheadAOffset:")==0 )
3416  {
3417  int temp;
3418  getint(sfd,&temp); sf->pfminfo.hheadascent_add = temp;
3419  }
3420  else if ( strmatch(tok,"HheadDescent:")==0 )
3421  {
3422  getsint(sfd,&sf->pfminfo.hhead_descent);
3423  }
3424  else if ( strmatch(tok,"HheadDOffset:")==0 )
3425  {
3426  int temp;
3427  getint(sfd,&temp); sf->pfminfo.hheaddescent_add = temp;
3428  }
3429  else if ( strmatch(tok,"OS2TypoLinegap:")==0 )
3430  {
3431  getsint(sfd,&sf->pfminfo.os2_typolinegap);
3432  }
3433  else if ( strmatch(tok,"OS2TypoAscent:")==0 )
3434  {
3435  getsint(sfd,&sf->pfminfo.os2_typoascent);
3436  }
3437  else if ( strmatch(tok,"OS2TypoAOffset:")==0 )
3438  {
3439  int temp;
3440  getint(sfd,&temp); sf->pfminfo.typoascent_add = temp;
3441  }
3442  else if ( strmatch(tok,"OS2TypoDescent:")==0 )
3443  {
3444  getsint(sfd,&sf->pfminfo.os2_typodescent);
3445  }
3446  else if ( strmatch(tok,"OS2TypoDOffset:")==0 )
3447  {
3448  int temp;
3449  getint(sfd,&temp); sf->pfminfo.typodescent_add = temp;
3450  }
3451  else if ( strmatch(tok,"OS2WinAscent:")==0 )
3452  {
3453  getsint(sfd,&sf->pfminfo.os2_winascent);
3454  }
3455  else if ( strmatch(tok,"OS2WinDescent:")==0 )
3456  {
3457  getsint(sfd,&sf->pfminfo.os2_windescent);
3458  }
3459  else if ( strmatch(tok,"OS2WinAOffset:")==0 )
3460  {
3461  int temp;
3462  getint(sfd,&temp); sf->pfminfo.winascent_add = temp;
3463  }
3464  else if ( strmatch(tok,"OS2WinDOffset:")==0 )
3465  {
3466  int temp;
3467  getint(sfd,&temp); sf->pfminfo.windescent_add = temp;
3468  }
3469  else if ( strmatch(tok,"HHeadAscent:")==0 )
3470  {
3471  // DUPLICATE OF ABOVE
3472  getsint(sfd,&sf->pfminfo.hhead_ascent);
3473  }
3474  else if ( strmatch(tok,"HHeadDescent:")==0 )
3475  {
3476  // DUPLICATE OF ABOVE
3477  getsint(sfd,&sf->pfminfo.hhead_descent);
3478  }
3479 
3480  else if ( strmatch(tok,"HHeadAOffset:")==0 )
3481  {
3482  // DUPLICATE OF ABOVE
3483  int temp;
3484  getint(sfd,&temp); sf->pfminfo.hheadascent_add = temp;
3485  }
3486  else if ( strmatch(tok,"HHeadDOffset:")==0 )
3487  {
3488  // DUPLICATE OF ABOVE
3489  int temp;
3490  getint(sfd,&temp); sf->pfminfo.hheaddescent_add = temp;
3491  }
3492  else if ( strmatch(tok,"MacStyle:")==0 )
3493  {
3494  getsint(sfd,&sf->macstyle);
3495  }
3496  else if ( strmatch(tok,"OS2SubXSize:")==0 )
3497  {
3498  getsint(sfd,&sf->pfminfo.os2_subxsize);
3499  sf->pfminfo.subsuper_set = true;
3500  }
3501  else if ( strmatch(tok,"OS2SubYSize:")==0 )
3502  {
3503  getsint(sfd,&sf->pfminfo.os2_subysize);
3504  }
3505  else if ( strmatch(tok,"OS2SubXOff:")==0 )
3506  {
3507  getsint(sfd,&sf->pfminfo.os2_subxoff);
3508  }
3509  else if ( strmatch(tok,"OS2SubYOff:")==0 )
3510  {
3511  getsint(sfd,&sf->pfminfo.os2_subyoff);
3512  }
3513  else if ( strmatch(tok,"OS2SupXSize:")==0 )
3514  {
3515  getsint(sfd,&sf->pfminfo.os2_supxsize);
3516  }
3517  else if ( strmatch(tok,"OS2SupYSize:")==0 )
3518  {
3519  getsint(sfd,&sf->pfminfo.os2_supysize);
3520  }
3521  else if ( strmatch(tok,"OS2SupXOff:")==0 )
3522  {
3523  getsint(sfd,&sf->pfminfo.os2_supxoff);
3524  }
3525  else if ( strmatch(tok,"OS2SupYOff:")==0 )
3526  {
3527  getsint(sfd,&sf->pfminfo.os2_supyoff);
3528  }
3529  else if ( strmatch(tok,"OS2StrikeYSize:")==0 )
3530  {
3531  getsint(sfd,&sf->pfminfo.os2_strikeysize);
3532  }
3533  else if ( strmatch(tok,"OS2StrikeYPos:")==0 )
3534  {
3535  getsint(sfd,&sf->pfminfo.os2_strikeypos);
3536  }
3537  else if ( strmatch(tok,"OS2CapHeight:")==0 )
3538  {
3539  getsint(sfd,&sf->pfminfo.os2_capheight);
3540  }
3541  else if ( strmatch(tok,"OS2XHeight:")==0 )
3542  {
3543  getsint(sfd,&sf->pfminfo.os2_xheight);
3544  }
3545  else if ( strmatch(tok,"OS2FamilyClass:")==0 )
3546  {
3547  getsint(sfd,&sf->pfminfo.os2_family_class);
3548  }
3549  else if ( strmatch(tok,"OS2Vendor:")==0 )
3550  {
3551  while ( isspace(nlgetc(sfd)));
3552  sf->pfminfo.os2_vendor[0] = nlgetc(sfd);
3553  sf->pfminfo.os2_vendor[1] = nlgetc(sfd);
3554  sf->pfminfo.os2_vendor[2] = nlgetc(sfd);
3555  sf->pfminfo.os2_vendor[3] = nlgetc(sfd);
3556  (void) nlgetc(sfd);
3557  }
3558  else if ( strmatch(tok,"OS2CodePages:")==0 )
3559  {
3560  gethexints(sfd,sf->pfminfo.codepages,2);
3561  sf->pfminfo.hascodepages = true;
3562  }
3563  else if ( strmatch(tok,"OS2UnicodeRanges:")==0 )
3564  {
3565  gethexints(sfd,