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
28 #include <fontforge-config.h>
29
30 #include "sfd.h"
31
32 #include "autohint.h"
33 #include "baseviews.h"
34 #include "bvedit.h"
35 #include "cvimages.h"
36 #include "cvundoes.h"
37 #include "encoding.h"
38 #include "ffglib.h"
39 #include "fontforge.h"
40 #include "fvfonts.h"
41 #include "gfile.h"
42 #include "gutils.h"
43 #include "gwidget.h"
44 #include "lookups.h"
45 #include "mem.h"
46 #include "namelist.h"
47 #include "parsettf.h"
48 #include "psread.h"
49 #include "sfd1.h"
50 #include "splinefill.h"
51 #include "splinefont.h"
52 #include "splineorder2.h"
53 #include "splinesaveafm.h"
54 #include "splineutil.h"
55 #include "splineutil2.h"
56 #include "tottfgpos.h"
57 #include "ttfinstrs.h"
58 #include "ustring.h"
59 #include "utype.h"
60 #include "views.h"
61
62 #include <dirent.h>
63 #include <limits.h> /* For NAME_MAX or _POSIX_NAME_MAX */
64 #include <locale.h>
65 #include <math.h>
66 #include <sys/stat.h>
67 #include <sys/types.h>
68 #include <unistd.h>
69 #include <stdio.h>
70
71 #ifdef _WIN32
72 #include <windows.h>
73 #endif
74
75 #ifndef NAME_MAX
76 # ifndef _POSIX_NAME_MAX
77 # define _POSIX_NAME_MAX 512
78 # endif
79 # define NAME_MAX _POSIX_NAME_MAX
80 #endif
81
82 int UndoRedoLimitToSave = 0;
83 int UndoRedoLimitToLoad = 0;
84
85 static const char *joins[] = { "miter", "round", "bevel", "inher", NULL };
86 static const char *caps[] = { "butt", "round", "square", "inher", NULL };
87 static const char *spreads[] = { "pad", "reflect", "repeat", NULL };
88
89 int prefRevisionsToRetain = 32;
90 #ifndef _NO_LIBPNG
91 int WritePNGInSFD = true;
92 #endif
93
94 #define SFD_PTFLAG_TYPE_MASK 0x3
95 #define SFD_PTFLAG_IS_SELECTED 0x4
96 #define SFD_PTFLAG_NEXTCP_IS_DEFAULT 0x8
97 #define SFD_PTFLAG_PREVCP_IS_DEFAULT 0x10
98 #define SFD_PTFLAG_ROUND_IN_X 0x20
99 #define SFD_PTFLAG_ROUND_IN_Y 0x40
100 #define SFD_PTFLAG_INTERPOLATE 0x80
101 #define SFD_PTFLAG_INTERPOLATE_NEVER 0x100
102 #define SFD_PTFLAG_PREV_EXTREMA_MARKED_ACCEPTABLE 0x200
103 #define SFD_PTFLAG_FORCE_OPEN_PATH 0x400
104
105
106
107
108 /* I will retain this list in case there are still some really old sfd files */
109 /* including numeric encodings. This table maps them to string encodings */
110 static const char *charset_names[] = {
111 "custom",
112 "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
113 "iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10",
114 "iso8859-11", "iso8859-13", "iso8859-14", "iso8859-15", "iso8859-16",
115 "koi8-r",
116 "jis201",
117 "win", "mac", "symbol", "zapfding", "adobestandard",
118 "jis208", "jis212", "ksc5601", "gb2312", "big5", "big5hkscs", "johab",
119 "unicode", "unicode4", "sjis", "wansung", "gb2312pk", NULL};
120
121 static const char *unicode_interp_names[] = { "none", "adobe", "greek",
122 "japanese", "tradchinese", "simpchinese", "korean", "ams", NULL };
123
124 /* sfdir files and extensions */
125 #define FONT_PROPS "font.props"
126 #define STRIKE_PROPS "strike.props"
127 #define EXT_CHAR '.'
128 #define GLYPH_EXT ".glyph"
129 #define BITMAP_EXT ".bitmap"
130 #define STRIKE_EXT ".strike"
131 #define SUBFONT_EXT ".subfont"
132 #define INSTANCE_EXT ".instance"
133
134 signed char inbase64[256] = {
135 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
136 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
137 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
138 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
139 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
140 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
141 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
142 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
143 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
144 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
145 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
146 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
147 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
148 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
149 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
151 };
152 static char base64[64] = {
153 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
154 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
155 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
156 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
157
158 static const char *end_tt_instrs = "EndTTInstrs";
159 static void SFDConsumeUntil( FILE *sfd, const char** terminators );
160 static void SFDDumpRefs(FILE *sfd,RefChar *refs, int *newgids);
161 static void SFDDumpGuidelines(FILE *sfd,GuidelineSet *gl);
162 static RefChar *SFDGetRef(FILE *sfd, int was_enc);
163 static void SFDDumpImage(FILE *sfd,ImageList *img);
164 #ifndef _NO_LIBPNG
165 static void SFDDumpImagePNG(FILE *sfd,ImageList *img);
166 #endif
167 static AnchorPoint *SFDReadAnchorPoints(FILE *sfd,SplineChar *sc,AnchorPoint** alist, AnchorPoint *lastap);
168 static GuidelineSet *SFDReadGuideline(FILE *sfd, GuidelineSet **gll, GuidelineSet *lastgl);
169 static void SFDDumpTtfInstrs(FILE *sfd,SplineChar *sc);
170 static void SFDDumpTtfInstrsExplicit(FILE *sfd,uint8 *ttf_instrs, int16 ttf_instrs_len );
171 static void SFDDumpHintList(FILE *sfd,const char *key, StemInfo *h);
172 static void SFDDumpDHintList( FILE *sfd,const char *key, DStemInfo *d );
173 static StemInfo *SFDReadHints(FILE *sfd);
174 static DStemInfo *SFDReadDHints( SplineFont *sf,FILE *sfd,int old );
175
PeekMatch(FILE * stream,const char * target)176 static int PeekMatch(FILE *stream, const char * target) {
177 // This returns 1 if target matches the next characters in the stream.
178 int pos1 = 0;
179 int lastread = getc(stream);
180 while (target[pos1] != '\0' && lastread != EOF && lastread == target[pos1]) {
181 pos1 ++; lastread = getc(stream);
182 }
183
184 int rewind_amount = pos1 + ((lastread == EOF) ? 0 : 1);
185 fseek(stream, -rewind_amount, SEEK_CUR);
186 return (target[pos1] == '\0');
187 }
188
utf7_encode(FILE * sfd,long ch)189 static void utf7_encode(FILE *sfd,long ch) {
190
191 putc(base64[(ch>>18)&0x3f],sfd);
192 putc(base64[(ch>>12)&0x3f],sfd);
193 putc(base64[(ch>>6)&0x3f],sfd);
194 putc(base64[ch&0x3f],sfd);
195 }
196
base64_encode(char * ostr,long ch)197 static char *base64_encode(char *ostr, long ch) {
198
199 *ostr++ = base64[(ch>>18)&0x3f];
200 *ostr++ = base64[(ch>>12)&0x3f];
201 *ostr++ = base64[(ch>> 6)&0x3f];
202 *ostr++ = base64[(ch )&0x3f];
203 return( ostr );
204 }
205
SFDDumpUTF7Str(FILE * sfd,const char * _str)206 static void SFDDumpUTF7Str(FILE *sfd, const char *_str) {
207 int ch, prev_cnt=0, prev=0, in=0;
208 const unsigned char *str = (const unsigned char *) _str;
209
210 putc('"',sfd);
211 if ( str!=NULL ) while ( (ch = *str++)!='\0' ) {
212 /* Convert from utf8 to ucs4 */
213 if ( ch<=127 )
214 /* Done */;
215 else if ( ch<=0xdf && *str!='\0' ) {
216 ch = ((ch&0x1f)<<6) | (*str++&0x3f);
217 } else if ( ch<=0xef && *str!='\0' && str[1]!='\0' ) {
218 ch = ((ch&0xf)<<12) | ((str[0]&0x3f)<<6) | (str[1]&0x3f);
219 str += 2;
220 } else if ( *str!='\0' && str[1]!='\0' && str[2]!='\0' ) {
221 int w = ( ((ch&0x7)<<2) | ((str[0]&0x30)>>4) )-1;
222 int s1, s2;
223 s1 = (w<<6) | ((str[0]&0xf)<<2) | ((str[1]&0x30)>>4);
224 s2 = ((str[1]&0xf)<<6) | (str[2]&0x3f);
225 ch = (s1*0x400)+s2 + 0x10000;
226 str += 3;
227 } else {
228 /* illegal */
229 }
230 if ( ch<127 && ch!='\n' && ch!='\r' && ch!='\\' && ch!='~' &&
231 ch!='+' && ch!='=' && ch!='"' ) {
232 if ( prev_cnt!=0 ) {
233 prev<<= (prev_cnt==1?16:8);
234 utf7_encode(sfd,prev);
235 prev_cnt=prev=0;
236 }
237 if ( in ) {
238 if ( inbase64[ch]!=-1 || ch=='-' )
239 putc('-',sfd);
240 in = 0;
241 }
242 putc(ch,sfd);
243 } else if ( ch=='+' && !in ) {
244 putc('+',sfd);
245 putc('-',sfd);
246 } else if ( prev_cnt== 0 ) {
247 if ( !in ) {
248 putc('+',sfd);
249 in = 1;
250 }
251 prev = ch;
252 prev_cnt = 2; /* 2 bytes */
253 } else if ( prev_cnt==2 ) {
254 prev<<=8;
255 prev += (ch>>8)&0xff;
256 utf7_encode(sfd,prev);
257 prev = (ch&0xff);
258 prev_cnt=1;
259 } else {
260 prev<<=16;
261 prev |= ch;
262 utf7_encode(sfd,prev);
263 prev_cnt = prev = 0;
264 }
265 }
266 if ( prev_cnt==2 ) {
267 prev<<=8;
268 utf7_encode(sfd,prev);
269 } else if ( prev_cnt==1 ) {
270 prev<<=16;
271 utf7_encode(sfd,prev);
272 }
273 putc('"',sfd);
274 }
275
276
utf8toutf7_copy(const char * _str)277 char *utf8toutf7_copy(const char *_str) {
278 int ch, prev_cnt=0, prev=0, in=0;
279 const unsigned char *str = (const unsigned char *) _str;
280 int i, len;
281 char *ret=NULL, *ostr=NULL;
282
283 if ( str==NULL )
284 return( NULL );
285 for ( i=0; i<2; ++i ) {
286 str = (const unsigned char *) _str;
287 len= prev_cnt= prev= in=0;
288 while ( (ch = *str++)!='\0' ) {
289 /* Convert from utf8 to ucs2 */
290 if ( ch<=127 )
291 /* Done */;
292 else if ( ch<=0xdf && *str!='\0' ) {
293 ch = ((ch&0x1f)<<6) | (*str++&0x3f);
294 } else if ( ch<=0xef && *str!='\0' && str[1]!='\0' ) {
295 ch = ((ch&0xf)<<12) | ((str[0]&0x3f)<<6) | (str[1]&0x3f);
296 str += 2;
297 } else if ( *str!='\0' && str[1]!='\0' && str[2]!='\0' ) {
298 int w = ( ((ch&0x7)<<2) | ((str[0]&0x30)>>4) )-1;
299 int s1, s2;
300 s1 = (w<<6) | ((str[0]&0xf)<<2) | ((str[1]&0x30)>>4);
301 s2 = ((str[1]&0xf)<<6) | (str[2]&0x3f);
302 ch = (s1*0x400)+s2 + 0x10000;
303 str += 3;
304 } else {
305 /* illegal */
306 }
307 if ( ch<127 && ch!='\n' && ch!='\r' && ch!='\\' && ch!='~' &&
308 ch!='+' && ch!='=' && ch!='"' ) {
309 if ( prev_cnt!=0 ) {
310 if ( i ) {
311 prev<<= (prev_cnt==1?16:8);
312 ostr = base64_encode(ostr,prev);
313 prev_cnt=prev=0;
314 } else
315 len += 4;
316 }
317 if ( in ) {
318 if ( inbase64[ch]!=-1 || ch=='-' ) {
319 if ( i )
320 *ostr++ = '-';
321 else
322 ++len;
323 }
324 in = 0;
325 }
326 if ( i )
327 *ostr++ = ch;
328 else
329 ++len;
330 } else if ( ch=='+' && !in ) {
331 if ( i ) {
332 *ostr++ = '+';
333 *ostr++ = '-';
334 } else
335 len += 2;
336 } else if ( prev_cnt== 0 ) {
337 if ( !in ) {
338 if ( i )
339 *ostr++ = '+';
340 else
341 ++len;
342 in = 1;
343 }
344 prev = ch;
345 prev_cnt = 2; /* 2 bytes */
346 } else if ( prev_cnt==2 ) {
347 prev<<=8;
348 prev += (ch>>8)&0xff;
349 if ( i ) {
350 ostr = base64_encode(ostr,prev);
351 prev_cnt=prev=0;
352 } else
353 len += 4;
354 prev = (ch&0xff);
355 prev_cnt=1;
356 } else {
357 prev<<=16;
358 prev |= ch;
359 if ( i ) {
360 ostr = base64_encode(ostr,prev);
361 prev_cnt=prev=0;
362 } else
363 len += 4;
364 prev_cnt = prev = 0;
365 }
366 }
367 if ( prev_cnt==2 ) {
368 prev<<=8;
369 if ( i ) {
370 ostr = base64_encode(ostr,prev);
371 prev_cnt=prev=0;
372 } else
373 len += 4;
374 } else if ( prev_cnt==1 ) {
375 prev<<=16;
376 if ( i ) {
377 ostr = base64_encode(ostr,prev);
378 prev_cnt=prev=0;
379 } else
380 len += 4;
381 }
382 if ( in ) {
383 if ( i )
384 *ostr++ = '-';
385 else
386 ++len;
387 }
388 if ( i==0 )
389 ostr = ret = malloc(len+1);
390 }
391 *ostr = '\0';
392 return( ret );
393 }
394
395 /* Long lines can be broken by inserting \\\n (backslash newline) */
396 /* into the line. I don't think this is ever ambiguous as I don't */
397 /* think a line can end with backslash */
398 /* UPDATE: it can... that's handled in getquotedeol() below. */
nlgetc(FILE * sfd)399 static int nlgetc(FILE *sfd) {
400 int ch, ch2;
401
402 ch=getc(sfd);
403 if ( ch!='\\' )
404 return( ch );
405 ch2 = getc(sfd);
406 if ( ch2=='\n' )
407 return( nlgetc(sfd));
408 ungetc(ch2,sfd);
409 return( ch );
410 }
411
SFDReadUTF7Str(FILE * sfd)412 static char *SFDReadUTF7Str(FILE *sfd) {
413 char *buffer = NULL, *pt, *end = NULL;
414 int ch1, ch2, ch3, ch4, done, c;
415 int prev_cnt=0, prev=0, in=0;
416
417 ch1 = nlgetc(sfd);
418 while ( isspace(ch1) && ch1!='\n' && ch1!='\r') ch1 = nlgetc(sfd);
419 if ( ch1=='\n' || ch1=='\r' )
420 ungetc(ch1,sfd);
421 if ( ch1!='"' )
422 return( NULL );
423 pt = 0;
424 while ( (ch1=nlgetc(sfd))!=EOF && ch1!='"' ) {
425 done = 0;
426 if ( !done && !in ) {
427 if ( ch1=='+' ) {
428 ch1 = nlgetc(sfd);
429 if ( ch1=='-' ) {
430 ch1 = '+';
431 done = true;
432 } else {
433 in = true;
434 prev_cnt = 0;
435 }
436 } else
437 done = true;
438 }
439 if ( !done ) {
440 if ( ch1=='-' ) {
441 in = false;
442 } else if ( inbase64[ch1]==-1 ) {
443 in = false;
444 done = true;
445 } else {
446 ch1 = inbase64[ch1];
447 ch2 = inbase64[c = nlgetc(sfd)];
448 if ( ch2==-1 ) {
449 ungetc(c, sfd);
450 ch2 = ch3 = ch4 = 0;
451 } else {
452 ch3 = inbase64[c = nlgetc(sfd)];
453 if ( ch3==-1 ) {
454 ungetc(c, sfd);
455 ch3 = ch4 = 0;
456 } else {
457 ch4 = inbase64[c = nlgetc(sfd)];
458 if ( ch4==-1 ) {
459 ungetc(c, sfd);
460 ch4 = 0;
461 }
462 }
463 }
464 ch1 = (ch1<<18) | (ch2<<12) | (ch3<<6) | ch4;
465 if ( prev_cnt==0 ) {
466 prev = ch1&0xff;
467 ch1 >>= 8;
468 prev_cnt = 1;
469 } else /* if ( prev_cnt == 1 ) */ {
470 ch1 |= (prev<<24);
471 prev = (ch1&0xffff);
472 ch1 = (ch1>>16)&0xffff;
473 prev_cnt = 2;
474 }
475 done = true;
476 }
477 }
478 if ( pt+10>=end ) {
479 if ( buffer==NULL ) {
480 pt = buffer = malloc(400);
481 end = buffer+400;
482 } else if (pt) {
483 char *temp = realloc(buffer,end-buffer+400);
484 pt = temp+(pt-buffer);
485 end = temp+(end-buffer+400);
486 buffer = temp;
487 }
488 }
489 if ( pt && done )
490 pt = utf8_idpb(pt,ch1,0);
491 if ( prev_cnt==2 ) {
492 prev_cnt = 0;
493 if ( pt && prev!=0 )
494 pt = utf8_idpb(pt,prev,0);
495 }
496 if ( pt==0 ) {
497 free(buffer);
498 return( NULL );
499 }
500 }
501 if ( buffer==NULL )
502 return( NULL );
503 *pt = '\0';
504 pt = copy(buffer);
505 free(buffer );
506 return( pt );
507 }
508
utf7toutf8_copy(const char * _str)509 char *utf7toutf8_copy(const char *_str) {
510 char *buffer = NULL, *pt, *end = NULL;
511 int ch1, ch2, ch3, ch4, done;
512 int prev_cnt=0, prev=0, in=0;
513 const char *str = _str;
514
515 if ( str==NULL )
516 return( NULL );
517 buffer = pt = malloc(400);
518 end = pt+400;
519 while ( (ch1=*str++)!='\0' ) {
520 done = 0;
521 if ( !done && !in ) {
522 if ( ch1=='+' ) {
523 ch1=*str++;
524 if ( ch1=='-' ) {
525 ch1 = '+';
526 done = true;
527 } else {
528 in = true;
529 prev_cnt = 0;
530 }
531 } else
532 done = true;
533 }
534 if ( !done ) {
535 if ( ch1=='-' ) {
536 in = false;
537 } else if ( inbase64[ch1]==-1 ) {
538 in = false;
539 done = true;
540 } else {
541 ch1 = inbase64[ch1];
542 ch2 = inbase64[(unsigned char) *str++];
543 if ( ch2==1 ) {
544 --str;
545 ch2 = ch3 = ch4 = 0;
546 } else {
547 ch3 = inbase64[(unsigned char) *str++];
548 if ( ch3==-1 ) {
549 --str;
550 ch3 = ch4 = 0;
551 } else {
552 ch4 = inbase64[(unsigned char) *str++];
553 if ( ch4==-1 ) {
554 --str;
555 ch4 = 0;
556 }
557 }
558 }
559 ch1 = (ch1<<18) | (ch2<<12) | (ch3<<6) | ch4;
560 if ( prev_cnt==0 ) {
561 prev = ch1&0xff;
562 ch1 >>= 8;
563 prev_cnt = 1;
564 } else /* if ( prev_cnt == 1 ) */ {
565 ch1 |= (prev<<24);
566 prev = (ch1&0xffff);
567 ch1 = (ch1>>16)&0xffff;
568 prev_cnt = 2;
569 }
570 done = true;
571 }
572 }
573 if ( pt+10>=end ) {
574 char *temp = realloc(buffer,end-buffer+400);
575 pt = temp+(pt-buffer);
576 end = temp+(end-buffer+400);
577 buffer = temp;
578 }
579 if ( pt && done )
580 pt = utf8_idpb(pt,ch1,0);
581 if ( prev_cnt==2 ) {
582 prev_cnt = 0;
583 if ( pt && prev!=0 )
584 pt = utf8_idpb(pt,prev,0);
585 }
586 if ( pt==0 ) {
587 free(buffer);
588 return( NULL );
589 }
590 }
591 *pt = '\0';
592 pt = copy(buffer);
593 free(buffer );
594 return( pt );
595 }
596
597 struct enc85 {
598 FILE *sfd;
599 unsigned char sofar[4];
600 int pos;
601 int ccnt;
602 };
603
SFDEnc85(struct enc85 * enc,int ch)604 static void SFDEnc85(struct enc85 *enc,int ch) {
605 enc->sofar[enc->pos++] = ch;
606 if ( enc->pos==4 ) {
607 unsigned int val = (enc->sofar[0]<<24)|(enc->sofar[1]<<16)|(enc->sofar[2]<<8)|enc->sofar[3];
608 if ( val==0 ) {
609 fputc('z',enc->sfd);
610 ++enc->ccnt;
611 } else {
612 int ch2, ch3, ch4, ch5;
613 ch5 = val%85;
614 val /= 85;
615 ch4 = val%85;
616 val /= 85;
617 ch3 = val%85;
618 val /= 85;
619 ch2 = val%85;
620 val /= 85;
621 fputc('!'+val,enc->sfd);
622 fputc('!'+ch2,enc->sfd);
623 fputc('!'+ch3,enc->sfd);
624 fputc('!'+ch4,enc->sfd);
625 fputc('!'+ch5,enc->sfd);
626 enc->ccnt += 5;
627 if ( enc->ccnt > 70 ) { fputc('\n',enc->sfd); enc->ccnt=0; }
628 }
629 enc->pos = 0;
630 }
631 }
632
SFDEnc85EndEnc(struct enc85 * enc)633 static void SFDEnc85EndEnc(struct enc85 *enc) {
634 int i;
635 int ch2, ch3, ch4, ch5;
636 unsigned val;
637 if ( enc->pos==0 )
638 return;
639 for ( i=enc->pos; i<4; ++i )
640 enc->sofar[i] = 0;
641 val = (enc->sofar[0]<<24)|(enc->sofar[1]<<16)|(enc->sofar[2]<<8)|enc->sofar[3];
642 if ( val==0 ) {
643 fputc('z',enc->sfd);
644 } else {
645 ch5 = val%85;
646 val /= 85;
647 ch4 = val%85;
648 val /= 85;
649 ch3 = val%85;
650 val /= 85;
651 ch2 = val%85;
652 val /= 85;
653 fputc('!'+val,enc->sfd);
654 fputc('!'+ch2,enc->sfd);
655 fputc('!'+ch3,enc->sfd);
656 fputc('!'+ch4,enc->sfd);
657 fputc('!'+ch5,enc->sfd);
658 }
659 enc->pos = 0;
660 }
661
SFDDumpHintMask(FILE * sfd,HintMask * hintmask)662 static void SFDDumpHintMask(FILE *sfd,HintMask *hintmask) {
663 unsigned i, j;
664
665 for ( i=HntMax/8-1; i>0; --i )
666 if ( (*hintmask)[i]!=0 )
667 break;
668 for ( j=0; /* j <= i, but that might never be true, so we test j == i at end of loop */ ; ++j ) {
669 if ( ((*hintmask)[j]>>4)<10 )
670 putc('0'+((*hintmask)[j]>>4),sfd);
671 else
672 putc('a'-10+((*hintmask)[j]>>4),sfd);
673 if ( ((*hintmask)[j]&0xf)<10 )
674 putc('0'+((*hintmask)[j]&0xf),sfd);
675 else
676 putc('a'-10+((*hintmask)[j]&0xf),sfd);
677 if (j == i) break;
678 }
679 }
680
SFDDumpSplineSet(FILE * sfd,SplineSet * spl,int want_order2)681 static void SFDDumpSplineSet(FILE *sfd, SplineSet *spl, int want_order2) {
682 SplinePoint *first, *sp;
683 // If there's no spline structure there should just be a single point,
684 // which is compatible with either order and therefore want_order2
685 int order2 = spl->first->next!=NULL ? spl->first->next->order2 : want_order2;
686 int reduce = (want_order2 && !order2);
687 if (order2 && !want_order2)
688 IError("Asked for cubic when had quadratic");
689 SplineSet *nspl;
690
691 for ( ; spl!=NULL; spl=spl->next ) {
692 if (reduce) {
693 nspl = SSttfApprox(spl);
694 order2 = true;
695 } else {
696 nspl = spl;
697 }
698 first = NULL;
699 for ( sp = nspl->first; ; sp=sp->next->to ) {
700 #ifndef FONTFORGE_CONFIG_USE_DOUBLE
701 if ( first==NULL )
702 fprintf( sfd, "%g %g m ", (double) sp->me.x, (double) sp->me.y );
703 else if ( sp->prev->islinear && sp->noprevcp ) /* Don't use known linear here. save control points if there are any */
704 fprintf( sfd, " %g %g l ", (double) sp->me.x, (double) sp->me.y );
705 else
706 fprintf( sfd, " %g %g %g %g %g %g c ",
707 (double) sp->prev->from->nextcp.x, (double) sp->prev->from->nextcp.y,
708 (double) sp->prevcp.x, (double) sp->prevcp.y,
709 (double) sp->me.x, (double) sp->me.y );
710 #else
711 if ( first==NULL )
712 fprintf( sfd, "%.12g %.12g m ", (double) sp->me.x, (double) sp->me.y );
713 else if ( sp->prev->islinear && sp->noprevcp ) /* Don't use known linear here. save control points if there are any */
714 fprintf( sfd, " %.12g %.12g l ", (double) sp->me.x, (double) sp->me.y );
715 else
716 fprintf( sfd, " %.12g %.12g %.12g %.12g %.12g %.12g c ",
717 (double) sp->prev->from->nextcp.x, (double) sp->prev->from->nextcp.y,
718 (double) sp->prevcp.x, (double) sp->prevcp.y,
719 (double) sp->me.x, (double) sp->me.y );
720 #endif
721 int ptflags = 0;
722 ptflags = sp->pointtype|(sp->selected<<2)|
723 (sp->nextcpdef<<3)|(sp->prevcpdef<<4)|
724 (sp->roundx<<5)|(sp->roundy<<6)|
725 (sp->ttfindex==0xffff?(1<<7):0)|
726 (sp->dontinterpolate<<8)|
727 ((sp->prev && sp->prev->acceptableextrema)<<9);
728
729 // Last point in the splineset, and we are an open path.
730 if( !sp->next
731 && spl->first && !spl->first->prev )
732 {
733 ptflags |= SFD_PTFLAG_FORCE_OPEN_PATH;
734 }
735
736
737 fprintf(sfd, "%d", ptflags );
738 if ( order2 ) {
739 if ( sp->ttfindex!=0xfffe && sp->nextcpindex!=0xfffe ) {
740 putc(',',sfd);
741 if ( sp->ttfindex==0xffff )
742 fprintf(sfd,"-1");
743 else if ( sp->ttfindex!=0xfffe )
744 fprintf(sfd,"%d",sp->ttfindex);
745 if ( sp->nextcpindex==0xffff )
746 fprintf(sfd,",-1");
747 else if ( sp->nextcpindex!=0xfffe )
748 fprintf(sfd,",%d",sp->nextcpindex);
749 }
750 } else {
751 if ( sp->hintmask!=NULL ) {
752 putc('x',sfd);
753 SFDDumpHintMask(sfd, sp->hintmask);
754 }
755 }
756 putc('\n',sfd);
757 if (sp->name != NULL) {
758 fputs("NamedP: ", sfd);
759 SFDDumpUTF7Str(sfd, sp->name);
760 putc('\n', sfd);
761 }
762 if ( sp==first )
763 break;
764 if ( first==NULL ) first = sp;
765 if ( sp->next==NULL )
766 break;
767 }
768 if ( spl->spiro_cnt!=0 ) {
769 int i;
770 fprintf( sfd, " Spiro\n" );
771 for ( i=0; i<spl->spiro_cnt; ++i ) {
772 fprintf( sfd, " %g %g %c\n", spl->spiros[i].x, spl->spiros[i].y,
773 spl->spiros[i].ty&0x7f);
774 }
775 fprintf( sfd, " EndSpiro\n" );
776 }
777 if ( spl->contour_name!=NULL ) {
778 fprintf( sfd, " Named: " );
779 SFDDumpUTF7Str(sfd,spl->contour_name);
780 putc('\n',sfd);
781 }
782 if ( spl->is_clip_path ) {
783 fprintf( sfd, " PathFlags: %d\n", spl->is_clip_path );
784 }
785 if ( spl->start_offset ) {
786 fprintf( sfd, " PathStart: %d\n", spl->start_offset );
787 }
788 if (reduce) SplinePointListFree(nspl);
789 }
790 fprintf( sfd, "EndSplineSet\n" );
791 }
792
SFDDumpDeviceTable(FILE * sfd,DeviceTable * adjust)793 static void SFDDumpDeviceTable(FILE *sfd,DeviceTable *adjust) {
794 int i;
795
796 if ( adjust==NULL )
797 return;
798 fprintf( sfd, "{" );
799 if ( adjust->corrections!=NULL ) {
800 fprintf( sfd, "%d-%d ", adjust->first_pixel_size, adjust->last_pixel_size );
801 for ( i=0; i<=adjust->last_pixel_size-adjust->first_pixel_size; ++i )
802 fprintf( sfd, "%s%d", i==0?"":",", adjust->corrections[i]);
803 }
804 fprintf( sfd, "}" );
805 }
806
SFDDumpValDevTab(FILE * sfd,ValDevTab * adjust)807 static void SFDDumpValDevTab(FILE *sfd,ValDevTab *adjust) {
808 if ( adjust==NULL )
809 return;
810 fprintf( sfd, " [ddx=" ); SFDDumpDeviceTable(sfd,&adjust->xadjust);
811 fprintf( sfd, " ddy=" ); SFDDumpDeviceTable(sfd,&adjust->yadjust);
812 fprintf( sfd, " ddh=" ); SFDDumpDeviceTable(sfd,&adjust->xadv);
813 fprintf( sfd, " ddv=" ); SFDDumpDeviceTable(sfd,&adjust->yadv);
814 putc(']',sfd);
815 }
816
SFDDumpAnchorPoints(FILE * sfd,AnchorPoint * ap)817 static void SFDDumpAnchorPoints(FILE *sfd,AnchorPoint *ap) {
818 if (ap==NULL) {
819 return;
820 }
821
822 for ( ; ap!=NULL; ap=ap->next )
823 {
824 fprintf( sfd, "AnchorPoint: " );
825 SFDDumpUTF7Str(sfd,ap->anchor->name);
826 putc(' ',sfd);
827 fprintf( sfd, "%g %g %s %d",
828 (double) ap->me.x, (double) ap->me.y,
829 ap->type==at_centry ? "entry" :
830 ap->type==at_cexit ? "exit" :
831 ap->type==at_mark ? "mark" :
832 ap->type==at_basechar ? "basechar" :
833 ap->type==at_baselig ? "baselig" : "basemark",
834 ap->lig_index );
835 if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ) {
836 putc(' ',sfd);
837 SFDDumpDeviceTable(sfd,&ap->xadjust);
838 putc(' ',sfd);
839 SFDDumpDeviceTable(sfd,&ap->yadjust);
840 } else
841 if ( ap->has_ttf_pt )
842 fprintf( sfd, " %d", ap->ttf_pt_index );
843 putc('\n',sfd);
844 }
845 }
846
847 /* Run length encoding */
848 /* We always start with a background pixel(1), each line is a series of counts */
849 /* we alternate background/foreground. If we can't represent an entire run */
850 /* as one count, then we can split it up into several smaller runs and put */
851 /* 0 counts in between */
852 /* counts 0-254 mean 0-254 pixels of the current color */
853 /* count 255 means that the next two bytes (bigendian) provide a two byte count */
854 /* count 255 0 n (n<255) means that the previous line should be repeated n+1 times */
855 /* count 255 0 255 means 255 pixels of the current color */
image2rle(struct _GImage * img,int * len)856 static uint8 *image2rle(struct _GImage *img, int *len) {
857 int max = img->height*img->bytes_per_line;
858 uint8 *rle, *pt, *end;
859 int cnt, set;
860 int i,j,k;
861
862 *len = 0;
863 if ( img->image_type!=it_mono || img->bytes_per_line<5 )
864 return( NULL );
865 rle = calloc(max,sizeof(uint8)), pt = rle, end=rle+max-3;
866
867 for ( i=0; i<img->height; ++i ) {
868 if ( i!=0 ) {
869 if ( memcmp(img->data+i*img->bytes_per_line,
870 img->data+(i-1)*img->bytes_per_line, img->bytes_per_line)== 0 ) {
871 for ( k=1; k<img->height-i; ++k ) {
872 if ( memcmp(img->data+(i+k)*img->bytes_per_line,
873 img->data+i*img->bytes_per_line, img->bytes_per_line)!= 0 )
874 break;
875 }
876 i+=k;
877 while ( k>0 ) {
878 if ( pt>end ) {
879 free(rle);
880 return( NULL );
881 }
882 *pt++ = 255;
883 *pt++ = 0;
884 *pt++ = k>254 ? 254 : k;
885 k -= 254;
886 }
887 if ( i>=img->height )
888 break;
889 }
890 }
891
892 set=1; cnt=0; j=0;
893 while ( j<img->width ) {
894 for ( k=j; k<img->width; ++k ) {
895 if (( set && !(img->data[i*img->bytes_per_line+(k>>3)]&(0x80>>(k&7))) ) ||
896 ( !set && (img->data[i*img->bytes_per_line+(k>>3)]&(0x80>>(k&7))) ))
897 break;
898 }
899 cnt = k-j;
900 j=k;
901 do {
902 if ( pt>=end ) {
903 free(rle);
904 return( NULL );
905 }
906 if ( cnt<=254 )
907 *pt++ = cnt;
908 else {
909 *pt++ = 255;
910 if ( cnt>65535 ) {
911 *pt++ = 255;
912 *pt++ = 255;
913 *pt++ = 0; /* nothing of the other color, we've still got more of this one */
914 } else {
915 *pt++ = cnt>>8;
916 *pt++ = cnt&0xff;
917 }
918 }
919 cnt -= 65535;
920 } while ( cnt>0 );
921 set = 1-set;
922 }
923 }
924 *len = pt-rle;
925 return( rle );
926 }
927
SFDDumpUndo(FILE * sfd,SplineChar * sc,Undoes * u,const char * keyPrefix,int idx)928 void SFDDumpUndo(FILE *sfd,SplineChar *sc,Undoes *u, const char* keyPrefix, int idx ) {
929 fprintf(sfd, "%sOperation\n", keyPrefix );
930 fprintf(sfd, "Index: %d\n", idx );
931 fprintf(sfd, "Type: %d\n", u->undotype );
932 fprintf(sfd, "WasModified: %d\n", u->was_modified );
933 fprintf(sfd, "WasOrder2: %d\n", u->was_order2 );
934 if( u->layer != UNDO_LAYER_UNKNOWN )
935 {
936 fprintf(sfd, "Layer: %d\n", u->layer );
937 }
938
939 switch( u->undotype )
940 {
941 case ut_tstate:
942 case ut_state:
943 fprintf(sfd, "Width: %d\n", u->u.state.width );
944 fprintf(sfd, "VWidth: %d\n", u->u.state.vwidth );
945 fprintf(sfd, "LBearingChange: %d\n", u->u.state.lbearingchange );
946 fprintf(sfd, "UnicodeEnc: %d\n", u->u.state.unicodeenc );
947 if( u->u.state.charname )
948 fprintf(sfd, "Charname: \"%s\"\n", u->u.state.charname );
949 if( u->u.state.comment )
950 fprintf(sfd, "Comment: \"%s\"\n", u->u.state.comment );
951 if( u->u.state.refs ) {
952 SFDDumpRefs( sfd, u->u.state.refs, 0 );
953 }
954 if( u->u.state.images ) {
955 #ifndef _NO_LIBPNG
956 if (WritePNGInSFD)
957 SFDDumpImagePNG( sfd, u->u.state.images );
958 else
959 #endif
960 SFDDumpImage( sfd, u->u.state.images );
961 }
962 fprintf(sfd, "InstructionsLength: %d\n", u->u.state.instrs_len );
963 if( u->u.state.anchor ) {
964 SFDDumpAnchorPoints( sfd, u->u.state.anchor );
965 }
966 if( u->u.state.splines ) {
967 fprintf(sfd, "SplineSet\n" );
968 SFDDumpSplineSet( sfd, u->u.state.splines, u->was_order2 );
969 }
970 break;
971
972 case ut_statehint:
973 {
974 SplineChar* tsc = 0;
975 tsc = SplineCharCopy( sc, 0, 0 );
976 ExtractHints( tsc, u->u.state.hints, 1 );
977 SFDDumpHintList( sfd, "HStem: ", tsc->hstem);
978 SFDDumpHintList( sfd, "VStem: ", tsc->vstem);
979 SFDDumpDHintList( sfd, "DStem2: ", tsc->dstem);
980 SplineCharFree( tsc );
981
982 if( u->u.state.instrs_len )
983 SFDDumpTtfInstrsExplicit( sfd, u->u.state.instrs, u->u.state.instrs_len );
984 break;
985 }
986
987 case ut_hints:
988 {
989 SplineChar* tsc = 0;
990 tsc = SplineCharCopy( sc, 0, 0 );
991 tsc->ttf_instrs = 0;
992 ExtractHints( tsc, u->u.state.hints, 1 );
993 SFDDumpHintList( sfd, "HStem: ", tsc->hstem);
994 SFDDumpHintList( sfd, "VStem: ", tsc->vstem);
995 SFDDumpDHintList( sfd, "DStem2: ", tsc->dstem);
996 SplineCharFree( tsc );
997
998 if( u->u.state.instrs_len )
999 SFDDumpTtfInstrsExplicit( sfd, u->u.state.instrs, u->u.state.instrs_len );
1000 if( u->copied_from && u->copied_from->fullname )
1001 fprintf(sfd, "CopiedFrom: %s\n", u->copied_from->fullname );
1002 break;
1003 }
1004
1005 case ut_width:
1006 case ut_vwidth:
1007 {
1008 fprintf(sfd, "Width: %d\n", u->u.width );
1009 break;
1010 }
1011
1012 default:
1013 break;
1014 }
1015
1016 fprintf(sfd, "End%sOperation\n", keyPrefix );
1017 }
1018
SFDDumpImage(FILE * sfd,ImageList * img)1019 static void SFDDumpImage(FILE *sfd,ImageList *img) {
1020 GImage *image = img->image;
1021 struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
1022 struct enc85 enc;
1023 int rlelen;
1024 uint8 *rle;
1025 int i;
1026
1027 rle = image2rle(base,&rlelen);
1028 fprintf(sfd, "Image: %d %d %d %d %d %x %g %g %g %g %d\n",
1029 (int) base->width, (int) base->height, base->image_type,
1030 (int) (base->image_type==it_true?3*base->width:base->bytes_per_line),
1031 base->clut==NULL?0:base->clut->clut_len,(int) base->trans,
1032 (double) img->xoff, (double) img->yoff, (double) img->xscale, (double) img->yscale, rlelen );
1033 memset(&enc,'\0',sizeof(enc));
1034 enc.sfd = sfd;
1035 if ( base->clut!=NULL ) {
1036 for ( i=0; i<base->clut->clut_len; ++i ) {
1037 SFDEnc85(&enc,base->clut->clut[i]>>16);
1038 SFDEnc85(&enc,(base->clut->clut[i]>>8)&0xff);
1039 SFDEnc85(&enc,base->clut->clut[i]&0xff);
1040 }
1041 }
1042 if ( rle!=NULL ) {
1043 uint8 *pt=rle, *end=rle+rlelen;
1044 while ( pt<end )
1045 SFDEnc85(&enc,*pt++);
1046 free( rle );
1047 } else {
1048 for ( i=0; i<base->height; ++i ) {
1049 if ( base->image_type==it_rgba ) {
1050 uint32 *ipt = (uint32 *) (base->data + i*base->bytes_per_line);
1051 uint32 *iend = (uint32 *) (base->data + (i+1)*base->bytes_per_line);
1052 while ( ipt<iend ) {
1053 SFDEnc85(&enc,*ipt>>24);
1054 SFDEnc85(&enc,(*ipt>>16)&0xff);
1055 SFDEnc85(&enc,(*ipt>>8)&0xff);
1056 SFDEnc85(&enc,*ipt&0xff);
1057 ++ipt;
1058 }
1059 } else if ( base->image_type==it_true ) {
1060 int *ipt = (int *) (base->data + i*base->bytes_per_line);
1061 int *iend = (int *) (base->data + (i+1)*base->bytes_per_line);
1062 while ( ipt<iend ) {
1063 SFDEnc85(&enc,*ipt>>16);
1064 SFDEnc85(&enc,(*ipt>>8)&0xff);
1065 SFDEnc85(&enc,*ipt&0xff);
1066 ++ipt;
1067 }
1068 } else {
1069 uint8 *pt = (uint8 *) (base->data + i*base->bytes_per_line);
1070 uint8 *end = (uint8 *) (base->data + (i+1)*base->bytes_per_line);
1071 while ( pt<end ) {
1072 SFDEnc85(&enc,*pt);
1073 ++pt;
1074 }
1075 }
1076 }
1077 }
1078 SFDEnc85EndEnc(&enc);
1079 fprintf(sfd,"\nEndImage\n" );
1080 }
1081
1082 #ifndef _NO_LIBPNG
SFDDumpImagePNG(FILE * sfd,ImageList * img)1083 static void SFDDumpImagePNG(FILE *sfd,ImageList *img) {
1084 struct enc85 enc = {0};
1085 char* pngbuf;
1086 size_t pnglen, i;
1087
1088 if (!GImageWritePngBuf(img->image, &pngbuf, &pnglen, 1, false)) {
1089 IError("Failed to serialise PNG image");
1090 return;
1091 }
1092
1093 fprintf(sfd, "Image2: image/png %d %g %g %g %g\n",
1094 (int)pnglen, (double) img->xoff, (double) img->yoff, (double) img->xscale, (double) img->yscale );
1095
1096 enc.sfd = sfd;
1097 for (i = 0; i<pnglen; ++i) {
1098 SFDEnc85(&enc, pngbuf[i]);
1099 }
1100 free(pngbuf);
1101
1102 SFDEnc85EndEnc(&enc);
1103 fprintf(sfd,"\nEndImage2\n" );
1104 }
1105 #endif
1106
SFDDumpHintList(FILE * sfd,const char * key,StemInfo * h)1107 static void SFDDumpHintList(FILE *sfd,const char *key, StemInfo *h) {
1108 HintInstance *hi;
1109
1110 if ( h==NULL )
1111 return;
1112 fprintf(sfd, "%s", key );
1113 for ( ; h!=NULL; h=h->next ) {
1114 fprintf(sfd, "%g %g", (double) h->start,(double) h->width );
1115 if ( h->ghost ) putc('G',sfd);
1116 if ( h->where!=NULL ) {
1117 putc('<',sfd);
1118 for ( hi=h->where; hi!=NULL; hi=hi->next )
1119 fprintf(sfd, "%g %g%c", (double) hi->begin, (double) hi->end, hi->next?' ':'>');
1120 }
1121 putc(h->next?' ':'\n',sfd);
1122 }
1123 }
1124
SFDDumpDHintList(FILE * sfd,const char * key,DStemInfo * d)1125 static void SFDDumpDHintList( FILE *sfd,const char *key, DStemInfo *d ) {
1126 HintInstance *hi;
1127
1128 if ( d==NULL )
1129 return;
1130 fprintf(sfd, "%s", key );
1131 for ( ; d!=NULL; d=d->next ) {
1132 fprintf(sfd, "%g %g %g %g %g %g",
1133 (double) d->left.x, (double) d->left.y,
1134 (double) d->right.x, (double) d->right.y,
1135 (double) d->unit.x, (double) d->unit.y );
1136 if ( d->where!=NULL ) {
1137 putc('<',sfd);
1138 for ( hi=d->where; hi!=NULL; hi=hi->next )
1139 fprintf(sfd, "%g %g%c", (double) hi->begin, (double) hi->end, hi->next?' ':'>');
1140 }
1141 putc(d->next?' ':'\n',sfd);
1142 }
1143 }
1144
SFDDumpTtfInstrsExplicit(FILE * sfd,uint8 * ttf_instrs,int16 ttf_instrs_len)1145 static void SFDDumpTtfInstrsExplicit(FILE *sfd,uint8 *ttf_instrs, int16 ttf_instrs_len )
1146 {
1147 char *instrs = _IVUnParseInstrs( ttf_instrs, ttf_instrs_len );
1148 char *pt;
1149 fprintf( sfd, "TtInstrs:\n" );
1150 for ( pt=instrs; *pt!='\0'; ++pt )
1151 putc(*pt,sfd);
1152 if ( pt[-1]!='\n' )
1153 putc('\n',sfd);
1154 free(instrs);
1155 fprintf( sfd, "%s\n", end_tt_instrs );
1156 }
SFDDumpTtfInstrs(FILE * sfd,SplineChar * sc)1157 static void SFDDumpTtfInstrs(FILE *sfd,SplineChar *sc)
1158 {
1159 SFDDumpTtfInstrsExplicit( sfd, sc->ttf_instrs,sc->ttf_instrs_len );
1160 }
1161
SFDDumpTtfTable(FILE * sfd,struct ttf_table * tab,SplineFont * sf)1162 static void SFDDumpTtfTable(FILE *sfd,struct ttf_table *tab,SplineFont *sf) {
1163 if ( tab->tag == CHR('p','r','e','p') || tab->tag == CHR('f','p','g','m') ) {
1164 /* These are tables of instructions and should be dumped as such */
1165 char *instrs;
1166 char *pt;
1167 fprintf( sfd, "TtTable: %c%c%c%c\n",
1168 (int) (tab->tag>>24), (int) ((tab->tag>>16)&0xff), (int) ((tab->tag>>8)&0xff), (int) (tab->tag&0xff) );
1169 instrs = _IVUnParseInstrs( tab->data,tab->len );
1170 for ( pt=instrs; *pt!='\0'; ++pt )
1171 putc(*pt,sfd);
1172 if ( pt[-1]!='\n' )
1173 putc('\n',sfd);
1174 free(instrs);
1175 fprintf( sfd, "%s\n", end_tt_instrs );
1176 } else if ( (tab->tag == CHR('c','v','t',' ') || tab->tag == CHR('m','a','x','p')) &&
1177 (tab->len&1)==0 ) {
1178 int i, ended;
1179 uint8 *pt;
1180 fprintf( sfd, "ShortTable: %c%c%c%c %d\n",
1181 (int) (tab->tag>>24), (int) ((tab->tag>>16)&0xff), (int) ((tab->tag>>8)&0xff), (int) (tab->tag&0xff),
1182 (int) (tab->len>>1) );
1183 pt = (uint8*) tab->data;
1184 ended = tab->tag!=CHR('c','v','t',' ') || sf->cvt_names==NULL;
1185 for ( i=0; i<(tab->len>>1); ++i ) {
1186 int num = (int16) ((pt[0]<<8) | pt[1]);
1187 fprintf( sfd, " %d", num );
1188 if ( !ended ) {
1189 if ( sf->cvt_names[i]==END_CVT_NAMES )
1190 ended=true;
1191 else if ( sf->cvt_names[i]!=NULL ) {
1192 putc(' ',sfd);
1193 SFDDumpUTF7Str(sfd,sf->cvt_names[i]);
1194 putc(' ',sfd);
1195 }
1196 }
1197 putc('\n',sfd);
1198 pt += 2;
1199 }
1200 fprintf( sfd, "EndShort\n");
1201 } else {
1202 /* maxp, who knows what. Dump 'em as binary for now */
1203 struct enc85 enc;
1204 int i;
1205
1206 memset(&enc,'\0',sizeof(enc));
1207 enc.sfd = sfd;
1208
1209 fprintf( sfd, "TtfTable: %c%c%c%c %d\n",
1210 (int) (tab->tag>>24), (int) ((tab->tag>>16)&0xff), (int) ((tab->tag>>8)&0xff), (int) (tab->tag&0xff),
1211 (int) tab->len );
1212 for ( i=0; i<tab->len; ++i )
1213 SFDEnc85(&enc,tab->data[i]);
1214 SFDEnc85EndEnc(&enc);
1215 fprintf(sfd,"\nEndTtf\n" );
1216 }
1217 }
1218
SFDOmit(SplineChar * sc)1219 static int SFDOmit(SplineChar *sc) {
1220 int layer;
1221 BDFFont *bdf;
1222
1223 if ( sc==NULL )
1224 return( true );
1225 if ( sc->comment!=NULL || sc->color!=COLOR_DEFAULT )
1226 return( false );
1227 for ( layer = ly_back; layer<sc->layer_cnt; ++layer ) {
1228 if ( sc->layers[layer].splines!=NULL ||
1229 sc->layers[layer].refs!=NULL ||
1230 sc->layers[layer].images!=NULL )
1231 return( false );
1232 }
1233 if ( sc->parent->onlybitmaps ) {
1234 for ( bdf = sc->parent->bitmaps; bdf!=NULL; bdf=bdf->next ) {
1235 if ( sc->orig_pos<bdf->glyphcnt && bdf->glyphs[sc->orig_pos]!=NULL )
1236 return( false );
1237 }
1238 }
1239 if ( !sc->widthset )
1240 return(true);
1241
1242 return( false );
1243 }
1244
SFDDumpRefs(FILE * sfd,RefChar * refs,int * newgids)1245 static void SFDDumpRefs(FILE *sfd,RefChar *refs, int *newgids) {
1246 RefChar *ref;
1247
1248 for ( ref=refs; ref!=NULL; ref=ref->next ) if ( ref->sc!=NULL ) {
1249 fprintf(sfd, "Refer: %d %d %c %g %g %g %g %g %g %d",
1250 newgids!=NULL ? newgids[ref->sc->orig_pos]:ref->sc->orig_pos,
1251 ref->sc->unicodeenc,
1252 ref->selected?'S':'N',
1253 (double) ref->transform[0], (double) ref->transform[1], (double) ref->transform[2],
1254 (double) ref->transform[3], (double) ref->transform[4], (double) ref->transform[5],
1255 ref->use_my_metrics|(ref->round_translation_to_grid<<1)|
1256 (ref->point_match<<2));
1257 if ( ref->point_match ) {
1258 fprintf(sfd, " %d %d", ref->match_pt_base, ref->match_pt_ref );
1259 if ( ref->point_match_out_of_date )
1260 fprintf( sfd, " O" );
1261 }
1262 putc('\n',sfd);
1263 }
1264 }
1265
SFDDumpGuidelines(FILE * sfd,GuidelineSet * gl)1266 static void SFDDumpGuidelines(FILE *sfd, GuidelineSet *gl) {
1267 if (gl==NULL) {
1268 return;
1269 }
1270
1271 for ( ; gl!=NULL; gl=gl->next )
1272 {
1273 fprintf( sfd, "Guideline: " );
1274 SFDDumpUTF7Str(sfd,gl->name);
1275 putc(' ',sfd);
1276 SFDDumpUTF7Str(sfd,gl->identifier);
1277 putc(' ',sfd);
1278 fprintf( sfd, "%g %g %g %u %d",
1279 (double) gl->point.x, (double) gl->point.y,
1280 (double) gl->angle, gl->color, gl->flags);
1281 putc('\n',sfd);
1282 }
1283 }
1284
SFDDumpMathVertex(FILE * sfd,struct mathkernvertex * vert,const char * name)1285 static void SFDDumpMathVertex(FILE *sfd,struct mathkernvertex *vert,const char *name) {
1286 int i;
1287
1288 if ( vert==NULL || vert->cnt==0 )
1289 return;
1290
1291 fprintf( sfd, "%s %d ", name, vert->cnt );
1292 for ( i=0; i<vert->cnt; ++i ) {
1293 fprintf( sfd, " %d", vert->mkd[i].height );
1294 SFDDumpDeviceTable(sfd,vert->mkd[i].height_adjusts );
1295 fprintf( sfd, ",%d", vert->mkd[i].kern );
1296 SFDDumpDeviceTable(sfd,vert->mkd[i].kern_adjusts );
1297 }
1298 putc('\n',sfd );
1299 }
1300
SFDDumpGlyphVariants(FILE * sfd,struct glyphvariants * gv,const char * name)1301 static void SFDDumpGlyphVariants(FILE *sfd,struct glyphvariants *gv,const char *name) {
1302 int i;
1303
1304 if ( gv==NULL )
1305 return;
1306
1307 if ( gv->variants!=NULL )
1308 fprintf( sfd, "GlyphVariants%s: %s\n", name, gv->variants );
1309 if ( gv->part_cnt!=0 ) {
1310 if ( gv->italic_correction!=0 ) {
1311 fprintf( sfd, "GlyphComposition%sIC: %d", name, gv->italic_correction );
1312 if ( gv->italic_adjusts!=NULL ) {
1313 putc(' ',sfd);
1314 SFDDumpDeviceTable(sfd,gv->italic_adjusts);
1315 }
1316 putc('\n',sfd);
1317 }
1318 fprintf( sfd, "GlyphComposition%s: %d ", name, gv->part_cnt );
1319 for ( i=0; i<gv->part_cnt; ++i ) {
1320 fprintf( sfd, " %s%%%d,%d,%d,%d", gv->parts[i].component,
1321 gv->parts[i].is_extender,
1322 gv->parts[i].startConnectorLength,
1323 gv->parts[i].endConnectorLength,
1324 gv->parts[i].fullAdvance);
1325 }
1326 putc('\n',sfd);
1327 }
1328 }
1329
SFDDumpCharMath(FILE * sfd,SplineChar * sc)1330 static void SFDDumpCharMath(FILE *sfd,SplineChar *sc) {
1331 if ( sc->italic_correction!=TEX_UNDEF && sc->italic_correction!=0 ) {
1332 fprintf( sfd, "ItalicCorrection: %d", sc->italic_correction );
1333 if ( sc->italic_adjusts!=NULL ) {
1334 putc(' ',sfd);
1335 SFDDumpDeviceTable(sfd,sc->italic_adjusts);
1336 }
1337 putc('\n',sfd);
1338 }
1339 if ( sc->top_accent_horiz!=TEX_UNDEF ) {
1340 fprintf( sfd, "TopAccentHorizontal: %d", sc->top_accent_horiz );
1341 if ( sc->top_accent_adjusts!=NULL ) {
1342 putc(' ',sfd);
1343 SFDDumpDeviceTable(sfd,sc->top_accent_adjusts);
1344 }
1345 putc('\n',sfd);
1346 }
1347 if ( sc->is_extended_shape )
1348 fprintf( sfd, "IsExtendedShape: %d\n", sc->is_extended_shape );
1349 SFDDumpGlyphVariants(sfd,sc->vert_variants,"Vertical");
1350 SFDDumpGlyphVariants(sfd,sc->horiz_variants,"Horizontal");
1351 if ( sc->mathkern!=NULL ) {
1352 SFDDumpMathVertex(sfd,&sc->mathkern->top_right,"TopRightVertex:");
1353 SFDDumpMathVertex(sfd,&sc->mathkern->top_left,"TopLeftVertex:");
1354 SFDDumpMathVertex(sfd,&sc->mathkern->bottom_right,"BottomRightVertex:");
1355 SFDDumpMathVertex(sfd,&sc->mathkern->bottom_left,"BottomLeftVertex:");
1356 }
1357 }
1358
SFDPickleMe(FILE * sfd,void * python_data,int python_data_has_lists)1359 static void SFDPickleMe(FILE *sfd,void *python_data, int python_data_has_lists) {
1360 char *string, *pt;
1361
1362 #ifdef _NO_PYTHON
1363 string = (char *) python_data;
1364 #else
1365 string = PyFF_PickleMeToString(python_data);
1366 #endif
1367 if ( string==NULL )
1368 return;
1369 if (python_data_has_lists)
1370 fprintf( sfd, "PickledDataWithLists: \"" );
1371 else
1372 fprintf( sfd, "PickledData: \"" );
1373 for ( pt=string; *pt; ++pt ) {
1374 if ( *pt=='\\' || *pt=='"' )
1375 putc('\\',sfd);
1376 putc(*pt,sfd);
1377 }
1378 fprintf( sfd, "\"\n");
1379 #ifndef _NO_PYTHON
1380 free(string);
1381 #endif
1382 }
1383
SFDUnPickle(FILE * sfd,int python_data_has_lists)1384 static void *SFDUnPickle(FILE *sfd, int python_data_has_lists) {
1385 int ch, quoted;
1386 static int max = 0;
1387 static char *buf = NULL;
1388 char *pt, *end;
1389 int cnt;
1390
1391 pt = buf; end = buf+max;
1392 while ( (ch=nlgetc(sfd))!='"' && ch!='\n' && ch!=EOF );
1393 if ( ch!='"' )
1394 return( NULL );
1395
1396 quoted = false;
1397 while ( ((ch=nlgetc(sfd))!='"' || quoted) && ch!=EOF ) {
1398 if ( !quoted && ch=='\\' )
1399 quoted = true;
1400 else {
1401 if ( pt>=end ) {
1402 cnt = pt-buf;
1403 buf = realloc(buf,(max+=200)+1);
1404 pt = buf+cnt;
1405 end = buf+max;
1406 }
1407 *pt++ = ch;
1408 quoted = false;
1409 }
1410 }
1411 if ( pt==buf )
1412 return( NULL );
1413 *pt='\0';
1414 #ifdef _NO_PYTHON
1415 return( copy(buf));
1416 #else
1417 return( PyFF_UnPickleMeToObjects(buf));
1418 #endif
1419 /* buf is a static buffer, I don't free it, I'll reuse it next time */
1420 }
1421
1422
SFDDumpGradient(FILE * sfd,const char * keyword,struct gradient * gradient)1423 static void SFDDumpGradient(FILE *sfd, const char *keyword, struct gradient *gradient) {
1424 int i;
1425
1426 /* Use ";" as a coord separator because we treat "," as a potential decimal point */
1427 fprintf( sfd, "%s %g;%g %g;%g %g %s %d ", keyword,
1428 (double) gradient->start.x, (double) gradient->start.y,
1429 (double) gradient->stop.x, (double) gradient->stop.y,
1430 (double) gradient->radius,
1431 spreads[gradient->sm],
1432 gradient->stop_cnt );
1433 for ( i=0 ; i<gradient->stop_cnt; ++i ) {
1434 fprintf( sfd, "{%g #%06x %g} ", (double) gradient->grad_stops[i].offset,
1435 gradient->grad_stops[i].col, (double) gradient->grad_stops[i].opacity );
1436 }
1437 putc('\n',sfd);
1438 }
1439
SFDDumpPattern(FILE * sfd,const char * keyword,struct pattern * pattern)1440 static void SFDDumpPattern(FILE *sfd, const char *keyword, struct pattern *pattern) {
1441
1442 fprintf( sfd, "%s %s %g;%g [%g %g %g %g %g %g]\n", keyword,
1443 pattern->pattern,
1444 (double) pattern->width, (double) pattern->height,
1445 (double) pattern->transform[0], (double) pattern->transform[1],
1446 (double) pattern->transform[2], (double) pattern->transform[3],
1447 (double) pattern->transform[4], (double) pattern->transform[5] );
1448 }
1449
SFD_DumpPST(FILE * sfd,SplineChar * sc)1450 void SFD_DumpPST( FILE *sfd, SplineChar *sc ) {
1451 PST *pst;
1452
1453 for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
1454 if (( pst->subtable==NULL && pst->type!=pst_lcaret) || pst->type==pst_null )
1455 /* Skip it */;
1456 else {
1457 static const char *keywords[] = { "Null:", "Position2:", "PairPos2:",
1458 "Substitution2:",
1459 "AlternateSubs2:", "MultipleSubs2:", "Ligature2:",
1460 "LCarets2:", NULL };
1461 fprintf( sfd, "%s ", keywords[pst->type] );
1462 if ( pst->subtable!=NULL ) {
1463 SFDDumpUTF7Str(sfd,pst->subtable->subtable_name);
1464 putc(' ',sfd);
1465 }
1466 if ( pst->type==pst_position ) {
1467 fprintf( sfd, "dx=%d dy=%d dh=%d dv=%d",
1468 pst->u.pos.xoff, pst->u.pos.yoff,
1469 pst->u.pos.h_adv_off, pst->u.pos.v_adv_off);
1470 SFDDumpValDevTab(sfd,pst->u.pos.adjust);
1471 putc('\n',sfd);
1472 } else if ( pst->type==pst_pair ) {
1473 fprintf( sfd, "%s dx=%d dy=%d dh=%d dv=%d",
1474 pst->u.pair.paired,
1475 pst->u.pair.vr[0].xoff, pst->u.pair.vr[0].yoff,
1476 pst->u.pair.vr[0].h_adv_off, pst->u.pair.vr[0].v_adv_off );
1477 SFDDumpValDevTab(sfd,pst->u.pair.vr[0].adjust);
1478 fprintf( sfd, " dx=%d dy=%d dh=%d dv=%d",
1479 pst->u.pair.vr[1].xoff, pst->u.pair.vr[1].yoff,
1480 pst->u.pair.vr[1].h_adv_off, pst->u.pair.vr[1].v_adv_off);
1481 SFDDumpValDevTab(sfd,pst->u.pair.vr[1].adjust);
1482 putc('\n',sfd);
1483 } else if ( pst->type==pst_lcaret ) {
1484 int i;
1485 fprintf( sfd, "%d ", pst->u.lcaret.cnt );
1486 for ( i=0; i<pst->u.lcaret.cnt; ++i ) {
1487 fprintf( sfd, "%d", pst->u.lcaret.carets[i] );
1488 if ( i<pst->u.lcaret.cnt-1 ) putc(' ',sfd);
1489 }
1490 fprintf( sfd, "\n" );
1491 } else
1492 fprintf( sfd, "%s\n", pst->u.lig.components );
1493 }
1494 }
1495 }
1496
1497
1498
SFD_DumpKerns(FILE * sfd,SplineChar * sc,int * newgids)1499 void SFD_DumpKerns( FILE *sfd, SplineChar *sc, int *newgids ) {
1500 KernPair *kp;
1501 int v;
1502
1503 for ( v=0; v<2; ++v ) {
1504 kp = v ? sc->vkerns : sc->kerns;
1505 if ( kp!=NULL ) {
1506 fprintf( sfd, v ? "VKerns2:" : "Kerns2:" );
1507 for ( ; kp!=NULL; kp=kp->next )
1508 if ( !SFDOmit(kp->sc)) {
1509 fprintf( sfd, " %d %d ",
1510 newgids!=NULL?newgids[kp->sc->orig_pos]:kp->sc->orig_pos,
1511 kp->off );
1512 SFDDumpUTF7Str(sfd,kp->subtable->subtable_name);
1513 if ( kp->adjust!=NULL ) putc(' ',sfd);
1514 SFDDumpDeviceTable(sfd,kp->adjust);
1515 }
1516 fprintf(sfd, "\n" );
1517 }
1518 }
1519 }
1520
SFDDumpCharStartingMarker(FILE * sfd,SplineChar * sc)1521 void SFDDumpCharStartingMarker(FILE *sfd,SplineChar *sc) {
1522 if ( AllAscii(sc->name))
1523 fprintf(sfd, "StartChar: %s\n", sc->name );
1524 else {
1525 fprintf(sfd, "StartChar: " );
1526 SFDDumpUTF7Str(sfd,sc->name);
1527 putc('\n',sfd);
1528 }
1529 }
1530
1531
SFDDumpChar(FILE * sfd,SplineChar * sc,EncMap * map,int * newgids,int todir,int saveUndoes)1532 static void SFDDumpChar(FILE *sfd,SplineChar *sc,EncMap *map,int *newgids,int todir,int saveUndoes) {
1533 // TODO: Output the U. F. O. glif name.
1534 ImageList *img;
1535 KernPair *kp;
1536 PST *pst;
1537 int i, v, enc;
1538 struct altuni *altuni;
1539
1540 if (!todir)
1541 putc('\n',sfd);
1542
1543 SFDDumpCharStartingMarker( sfd, sc );
1544 if ( (enc = map->backmap[sc->orig_pos])>=map->enccount ) {
1545 if ( sc->parent->cidmaster==NULL )
1546 IError("Bad reverse encoding");
1547 enc = -1;
1548 }
1549 if ( sc->unicodeenc!=-1 &&
1550 ((map->enc->is_unicodebmp && sc->unicodeenc<0x10000) ||
1551 (map->enc->is_unicodefull && sc->unicodeenc < (int)unicode4_size)) )
1552 /* If we have altunis, then the backmap may not give the primary */
1553 /* unicode code point, which is what we need here */
1554 fprintf(sfd, "Encoding: %d %d %d\n", sc->unicodeenc, sc->unicodeenc,
1555 newgids!=NULL?newgids[sc->orig_pos]:sc->orig_pos);
1556 else
1557 fprintf(sfd, "Encoding: %d %d %d\n", enc, sc->unicodeenc,
1558 newgids!=NULL?newgids[sc->orig_pos]:sc->orig_pos);
1559 if ( sc->altuni ) {
1560 fprintf( sfd, "AltUni2:" );
1561 for ( altuni = sc->altuni; altuni!=NULL; altuni=altuni->next )
1562 fprintf( sfd, " %06x.%06x.%x", altuni->unienc, altuni->vs, altuni->fid );
1563 putc( '\n', sfd);
1564 }
1565 if ( sc->glif_name ) {
1566 fprintf(sfd, "GlifName: ");
1567 if ( AllAscii(sc->glif_name))
1568 fprintf(sfd, "%s", sc->glif_name );
1569 else {
1570 SFDDumpUTF7Str(sfd,sc->glif_name);
1571 }
1572 putc('\n',sfd);
1573 }
1574 fprintf(sfd, "Width: %d\n", sc->width );
1575 if ( sc->vwidth!=sc->parent->ascent+sc->parent->descent )
1576 fprintf(sfd, "VWidth: %d\n", sc->vwidth );
1577 if ( sc->glyph_class!=0 )
1578 fprintf(sfd, "GlyphClass: %d\n", sc->glyph_class );
1579 if ( sc->unlink_rm_ovrlp_save_undo )
1580 fprintf(sfd, "UnlinkRmOvrlpSave: %d\n", sc->unlink_rm_ovrlp_save_undo );
1581 if ( sc->inspiro )
1582 fprintf(sfd, "InSpiro: %d\n", sc->inspiro );
1583 if ( sc->lig_caret_cnt_fixed )
1584 fprintf(sfd, "LigCaretCntFixed: %d\n", sc->lig_caret_cnt_fixed );
1585 if ( sc->changedsincelasthinted|| sc->manualhints || sc->widthset )
1586 fprintf(sfd, "Flags: %s%s%s%s%s\n",
1587 sc->changedsincelasthinted?"H":"",
1588 sc->manualhints?"M":"",
1589 sc->widthset?"W":"",
1590 sc->views!=NULL?"O":"",
1591 sc->instructions_out_of_date?"I":"");
1592 if ( sc->tex_height!=TEX_UNDEF || sc->tex_depth!=TEX_UNDEF )
1593 fprintf( sfd, "TeX: %d %d\n", sc->tex_height, sc->tex_depth );
1594 if ( sc->is_extended_shape || sc->italic_correction!=TEX_UNDEF ||
1595 sc->top_accent_horiz!=TEX_UNDEF || sc->vert_variants!=NULL ||
1596 sc->horiz_variants!=NULL || sc->mathkern!=NULL )
1597 SFDDumpCharMath(sfd,sc);
1598 #if HANYANG
1599 if ( sc->compositionunit )
1600 fprintf( sfd, "CompositionUnit: %d %d\n", sc->jamo, sc->varient );
1601 #endif
1602 SFDDumpHintList(sfd,"HStem: ", sc->hstem);
1603 SFDDumpHintList(sfd,"VStem: ", sc->vstem);
1604 SFDDumpDHintList(sfd,"DStem2: ", sc->dstem);
1605 if ( sc->countermask_cnt!=0 ) {
1606 fprintf( sfd, "CounterMasks: %d", sc->countermask_cnt );
1607 for ( i=0; i<sc->countermask_cnt; ++i ) {
1608 putc(' ',sfd);
1609 SFDDumpHintMask(sfd,&sc->countermasks[i]);
1610 }
1611 putc('\n',sfd);
1612 }
1613 if ( sc->ttf_instrs_len!=0 )
1614 SFDDumpTtfInstrs(sfd,sc);
1615 SFDDumpAnchorPoints(sfd,sc->anchor);
1616 fprintf( sfd, "LayerCount: %d\n", sc->layer_cnt );
1617 for ( i=0; i<sc->layer_cnt; ++i ) {
1618 if( saveUndoes && UndoRedoLimitToSave > 0) {
1619 if( sc->layers[i].undoes || sc->layers[i].redoes ) {
1620 fprintf(sfd, "UndoRedoHistory\n" );
1621 fprintf(sfd, "Layer: %d\n", i );
1622 Undoes *undo = 0;
1623 int idx = 0;
1624 int limit = 0;
1625
1626 fprintf(sfd, "Undoes\n" );
1627 idx = 0;
1628 undo = sc->layers[i].undoes;
1629 for( limit = UndoRedoLimitToSave;
1630 undo && (limit==-1 || limit>0);
1631 undo = undo->next, idx++ ) {
1632 SFDDumpUndo( sfd, sc, undo, "Undo", idx );
1633 if( limit > 0 )
1634 limit--;
1635 }
1636 fprintf(sfd, "EndUndoes\n" );
1637
1638 fprintf(sfd, "Redoes\n" );
1639 idx = 0;
1640 limit = UndoRedoLimitToSave;
1641 undo = sc->layers[i].redoes;
1642 for( limit = UndoRedoLimitToSave;
1643 undo && (limit==-1 || limit>0);
1644 undo = undo->next, idx++ ) {
1645 SFDDumpUndo( sfd, sc, undo, "Redo", idx );
1646 if( limit > 0 )
1647 limit--;
1648 }
1649 fprintf(sfd, "EndRedoes\n" );
1650 fprintf(sfd, "EndUndoRedoHistory\n" );
1651 }
1652 }
1653
1654 if ( sc->parent->multilayer ) {
1655 fprintf(sfd, "Layer: %d %d %d %d #%06x %g #%06x %g %g %s %s [%g %g %g %g] [",
1656 i, sc->layers[i].dofill, sc->layers[i].dostroke, sc->layers[i].fillfirst,
1657 sc->layers[i].fill_brush.col, (double) sc->layers[i].fill_brush.opacity,
1658 sc->layers[i].stroke_pen.brush.col, (double) sc->layers[i].stroke_pen.brush.opacity,
1659 (double) sc->layers[i].stroke_pen.width, joins[sc->layers[i].stroke_pen.linejoin], caps[sc->layers[i].stroke_pen.linecap],
1660 (double) sc->layers[i].stroke_pen.trans[0], (double) sc->layers[i].stroke_pen.trans[1],
1661 (double) sc->layers[i].stroke_pen.trans[2], (double) sc->layers[i].stroke_pen.trans[3] );
1662 if ( sc->layers[i].stroke_pen.dashes[0]==0 && sc->layers[i].stroke_pen.dashes[1]==DASH_INHERITED )
1663 fprintf(sfd,"0 %d]\n", DASH_INHERITED);
1664 else { int j;
1665 for ( j=0; j<DASH_MAX && sc->layers[i].stroke_pen.dashes[j]!=0; ++j )
1666 fprintf( sfd,"%d ", sc->layers[i].stroke_pen.dashes[j]);
1667 fprintf(sfd,"]\n");
1668 }
1669 if ( sc->layers[i].fill_brush.gradient!=NULL )
1670 SFDDumpGradient(sfd,"FillGradient:", sc->layers[i].fill_brush.gradient );
1671 else if ( sc->layers[i].fill_brush.pattern!=NULL )
1672 SFDDumpPattern(sfd,"FillPattern:", sc->layers[i].fill_brush.pattern );
1673 if ( sc->layers[i].stroke_pen.brush.gradient!=NULL )
1674 SFDDumpGradient(sfd,"StrokeGradient:", sc->layers[i].stroke_pen.brush.gradient );
1675 else if ( sc->layers[i].stroke_pen.brush.pattern!=NULL )
1676 SFDDumpPattern(sfd,"StrokePattern:", sc->layers[i].stroke_pen.brush.pattern );
1677 } else {
1678 if ( sc->layers[i].images==NULL && sc->layers[i].splines==NULL &&
1679 sc->layers[i].refs==NULL && (sc->layers[i].validation_state&vs_known) == 0 &&
1680 sc->layers[i].python_persistent == NULL)
1681 continue;
1682 if ( i==ly_back )
1683 fprintf( sfd, "Back\n" );
1684 else if ( i==ly_fore )
1685 fprintf( sfd, "Fore\n" );
1686 else
1687 fprintf(sfd, "Layer: %d\n", i );
1688 }
1689 for ( img=sc->layers[i].images; img!=NULL; img=img->next )
1690 #ifndef _NO_LIBPNG
1691 if (WritePNGInSFD)
1692 SFDDumpImagePNG(sfd,img);
1693 else
1694 #endif
1695 SFDDumpImage(sfd,img);
1696 if ( sc->layers[i].splines!=NULL ) {
1697 fprintf(sfd, "SplineSet\n" );
1698 SFDDumpSplineSet(sfd,sc->layers[i].splines,sc->layers[i].order2);
1699 }
1700 SFDDumpRefs(sfd,sc->layers[i].refs,newgids);
1701 SFDDumpGuidelines(sfd, sc->layers[i].guidelines);
1702 if ( sc->layers[i].validation_state&vs_known )
1703 fprintf( sfd, "Validated: %d\n", sc->layers[i].validation_state );
1704 if ( sc->layers[i].python_persistent!=NULL )
1705 SFDPickleMe(sfd,sc->layers[i].python_persistent,sc->layers[i].python_persistent_has_lists);
1706 }
1707 for ( v=0; v<2; ++v ) {
1708 kp = v ? sc->vkerns : sc->kerns;
1709 if ( kp!=NULL ) {
1710 fprintf( sfd, v ? "VKerns2:" : "Kerns2:" );
1711 for ( ; kp!=NULL; kp=kp->next ) {
1712 if ( !SFDOmit(kp->sc)) {
1713 fprintf( sfd, " %d %d ",
1714 newgids!=NULL?newgids[kp->sc->orig_pos]:kp->sc->orig_pos,
1715 kp->off );
1716 SFDDumpUTF7Str(sfd,kp->subtable->subtable_name);
1717 if ( kp->adjust!=NULL ) putc(' ',sfd);
1718 SFDDumpDeviceTable(sfd,kp->adjust);
1719 }
1720 }
1721 fprintf(sfd, "\n" );
1722 }
1723 }
1724 for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
1725 if (( pst->subtable==NULL && pst->type!=pst_lcaret) || pst->type==pst_null )
1726 /* Skip it */;
1727 else {
1728 static const char *keywords[] = { "Null:", "Position2:", "PairPos2:",
1729 "Substitution2:",
1730 "AlternateSubs2:", "MultipleSubs2:", "Ligature2:",
1731 "LCarets2:", NULL };
1732 fprintf( sfd, "%s ", keywords[pst->type] );
1733 if ( pst->subtable!=NULL ) {
1734 SFDDumpUTF7Str(sfd,pst->subtable->subtable_name);
1735 putc(' ',sfd);
1736 }
1737 if ( pst->type==pst_position ) {
1738 fprintf( sfd, "dx=%d dy=%d dh=%d dv=%d",
1739 pst->u.pos.xoff, pst->u.pos.yoff,
1740 pst->u.pos.h_adv_off, pst->u.pos.v_adv_off);
1741 SFDDumpValDevTab(sfd,pst->u.pos.adjust);
1742 putc('\n',sfd);
1743 } else if ( pst->type==pst_pair ) {
1744 fprintf( sfd, "%s dx=%d dy=%d dh=%d dv=%d",
1745 pst->u.pair.paired,
1746 pst->u.pair.vr[0].xoff, pst->u.pair.vr[0].yoff,
1747 pst->u.pair.vr[0].h_adv_off, pst->u.pair.vr[0].v_adv_off );
1748 SFDDumpValDevTab(sfd,pst->u.pair.vr[0].adjust);
1749 fprintf( sfd, " dx=%d dy=%d dh=%d dv=%d",
1750 pst->u.pair.vr[1].xoff, pst->u.pair.vr[1].yoff,
1751 pst->u.pair.vr[1].h_adv_off, pst->u.pair.vr[1].v_adv_off);
1752 SFDDumpValDevTab(sfd,pst->u.pair.vr[1].adjust);
1753 putc('\n',sfd);
1754 } else if ( pst->type==pst_lcaret ) {
1755 int i;
1756 fprintf( sfd, "%d ", pst->u.lcaret.cnt );
1757 for ( i=0; i<pst->u.lcaret.cnt; ++i ) {
1758 fprintf( sfd, "%d", pst->u.lcaret.carets[i] );
1759 if ( i<pst->u.lcaret.cnt-1 ) putc(' ',sfd);
1760 }
1761 fprintf( sfd, "\n" );
1762 } else
1763 fprintf( sfd, "%s\n", pst->u.lig.components );
1764 }
1765 }
1766 if ( sc->comment!=NULL ) {
1767 fprintf( sfd, "Comment: " );
1768 SFDDumpUTF7Str(sfd,sc->comment);
1769 putc('\n',sfd);
1770 }
1771 if ( sc->user_decomp != NULL ) {
1772 fprintf( sfd, "Decomposition: " );
1773 char* temp_ud = u2utf8_copy(sc->user_decomp);
1774 SFDDumpUTF7Str(sfd, temp_ud);
1775 free(temp_ud);
1776 putc('\n',sfd);
1777 }
1778 if ( sc->color!=COLOR_DEFAULT )
1779 fprintf( sfd, "Colour: %x\n", (int) sc->color );
1780 if ( sc->parent->multilayer ) {
1781 if ( sc->tile_margin!=0 )
1782 fprintf( sfd, "TileMargin: %g\n", (double) sc->tile_margin );
1783 else if ( sc->tile_bounds.minx!=0 || sc->tile_bounds.maxx!=0 )
1784 fprintf( sfd, "TileBounds: %g %g %g %g\n", (double) sc->tile_bounds.minx, (double) sc->tile_bounds.miny, (double) sc->tile_bounds.maxx, (double) sc->tile_bounds.maxy );
1785 }
1786 fprintf(sfd,"EndChar\n" );
1787 }
1788
SFDDumpBitmapChar(FILE * sfd,BDFChar * bfc,int enc,int * newgids)1789 static void SFDDumpBitmapChar(FILE *sfd,BDFChar *bfc, int enc,int *newgids) {
1790 struct enc85 encrypt;
1791 int i;
1792
1793 fprintf(sfd, "BDFChar: %d %d %d %d %d %d %d",
1794 newgids!=NULL ? newgids[bfc->orig_pos] : bfc->orig_pos, enc,
1795 bfc->width, bfc->xmin, bfc->xmax, bfc->ymin, bfc->ymax );
1796 if ( bfc->sc->parent->hasvmetrics )
1797 fprintf(sfd, " %d", bfc->vwidth);
1798 putc('\n',sfd);
1799 memset(&encrypt,'\0',sizeof(encrypt));
1800 encrypt.sfd = sfd;
1801 for ( i=0; i<=bfc->ymax-bfc->ymin; ++i ) {
1802 uint8 *pt = (uint8 *) (bfc->bitmap + i*bfc->bytes_per_line);
1803 uint8 *end = pt + bfc->bytes_per_line;
1804 while ( pt<end ) {
1805 SFDEnc85(&encrypt,*pt);
1806 ++pt;
1807 }
1808 }
1809 SFDEnc85EndEnc(&encrypt);
1810 fputc('\n',sfd);
1811 }
1812
appendnames(char * dest,char * dir,const char * dir_char,char * name,const char * ext)1813 static void appendnames(char *dest,char *dir,const char *dir_char,char *name,const char *ext ) {
1814 strcpy(dest,dir);
1815 dest += strlen(dest);
1816 strcpy(dest,dir_char);
1817 dest += strlen(dest);
1818 /* Some file systems are case-insensitive, so we can't just */
1819 /* copy the glyph name blindly (else "A" and "a" would map to the same file */
1820 for (;;) {
1821 if ( strncmp(name,"uni",3)==0 && ishexdigit(name[3]) && ishexdigit(name[4]) &&
1822 ishexdigit(name[5]) && ishexdigit(name[6])) {
1823 /* but in a name like uni00AD case is irrelevant. Even under unix its */
1824 /* the same as uni00ad -- and it looks ugly */
1825 strncpy(dest,name,7);
1826 dest += 7; name += 7;
1827 while ( ishexdigit(name[0]) && ishexdigit(name[1]) &&
1828 ishexdigit(name[2]) && ishexdigit(name[3]) ) {
1829 strncpy(dest,name,4);
1830 dest += 4; name += 4;
1831 }
1832 } else if ( name[0]=='u' && ishexdigit(name[1]) && ishexdigit(name[2]) &&
1833 ishexdigit(name[3]) && ishexdigit(name[4]) &&
1834 ishexdigit(name[5]) ) {
1835 strncpy(dest,name,5);
1836 dest += 5; name += 5;
1837 } else
1838 break;
1839 if ( *name!='_' )
1840 break;
1841 *dest++ = '_';
1842 ++name;
1843 }
1844 while ( *name ) {
1845 if ( isupper(*name)) {
1846 *dest++ = '_';
1847 *dest++ = *name;
1848 } else
1849 *dest++ = *name;
1850 ++name;
1851 }
1852 strcpy(dest,ext);
1853 }
1854
SFDDumpBitmapFont(FILE * sfd,BDFFont * bdf,EncMap * encm,int * newgids,int todir,char * dirname)1855 static int SFDDumpBitmapFont(FILE *sfd,BDFFont *bdf,EncMap *encm,int *newgids,
1856 int todir, char *dirname) {
1857 int i;
1858 int err = false;
1859 BDFChar *bc;
1860 BDFRefChar *ref;
1861
1862 ff_progress_next_stage();
1863 if (bdf->foundry)
1864 fprintf( sfd, "BitmapFont: %d %d %d %d %d %s\n", bdf->pixelsize, bdf->glyphcnt,
1865 bdf->ascent, bdf->descent, BDFDepth(bdf), bdf->foundry );
1866 else
1867 fprintf( sfd, "BitmapFont: %d %d %d %d %d\n", bdf->pixelsize, bdf->glyphcnt,
1868 bdf->ascent, bdf->descent, BDFDepth(bdf) );
1869 if ( bdf->prop_cnt>0 ) {
1870 fprintf( sfd, "BDFStartProperties: %d\n", bdf->prop_cnt );
1871 for ( i=0; i<bdf->prop_cnt; ++i ) {
1872 fprintf(sfd,"%s %d ", bdf->props[i].name, bdf->props[i].type );
1873 switch ( bdf->props[i].type&~prt_property ) {
1874 case prt_int: case prt_uint:
1875 fprintf(sfd, "%d\n", bdf->props[i].u.val );
1876 break;
1877 case prt_string: case prt_atom:
1878 fprintf(sfd, "\"%s\"\n", bdf->props[i].u.str );
1879 break;
1880 default:
1881 break;
1882 }
1883 }
1884 fprintf( sfd, "BDFEndProperties\n" );
1885 }
1886 if ( bdf->res>20 )
1887 fprintf( sfd, "Resolution: %d\n", bdf->res );
1888 for ( i=0; i<bdf->glyphcnt; ++i ) {
1889 if ( bdf->glyphs[i]!=NULL ) {
1890 if ( todir ) {
1891 char *glyphfile = malloc(strlen(dirname)+2*strlen(bdf->glyphs[i]->sc->name)+20);
1892 FILE *gsfd;
1893 appendnames(glyphfile,dirname,"/",bdf->glyphs[i]->sc->name,BITMAP_EXT );
1894 gsfd = fopen(glyphfile,"w");
1895 if ( gsfd!=NULL ) {
1896 SFDDumpBitmapChar(gsfd,bdf->glyphs[i],encm->backmap[i],newgids);
1897 if ( ferror(gsfd)) err = true;
1898 if ( fclose(gsfd)) err = true;
1899 } else
1900 err = true;
1901 free(glyphfile);
1902 } else
1903 SFDDumpBitmapChar(sfd,bdf->glyphs[i],encm->backmap[i],newgids);
1904 }
1905 ff_progress_next();
1906 }
1907 for ( i=0; i<bdf->glyphcnt; ++i ) if (( bc = bdf->glyphs[i] ) != NULL ) {
1908 for ( ref=bc->refs; ref!=NULL; ref=ref->next )
1909 fprintf(sfd, "BDFRefChar: %d %d %d %d %c\n",
1910 newgids!=NULL ? newgids[bc->orig_pos] : bc->orig_pos,
1911 newgids!=NULL ? newgids[ref->bdfc->orig_pos] : ref->bdfc->orig_pos,
1912 ref->xoff,ref->yoff,ref->selected?'S':'N' );
1913 }
1914 fprintf( sfd, "EndBitmapFont\n" );
1915 return( err );
1916 }
1917
SFDDumpPrivate(FILE * sfd,struct psdict * private)1918 static void SFDDumpPrivate(FILE *sfd,struct psdict *private) {
1919 int i;
1920 char *pt;
1921 /* These guys should all be ascii text */
1922 fprintf( sfd, "BeginPrivate: %d\n", private->next );
1923 for ( i=0; i<private->next ; ++i ) {
1924 fprintf( sfd, "%s %d ", private->keys[i],
1925 (int)strlen(private->values[i]));
1926 for ( pt = private->values[i]; *pt; ++pt )
1927 putc(*pt,sfd);
1928 putc('\n',sfd);
1929 }
1930 fprintf( sfd, "EndPrivate\n" );
1931 }
1932
SFDDumpLangName(FILE * sfd,struct ttflangname * ln)1933 static void SFDDumpLangName(FILE *sfd, struct ttflangname *ln) {
1934 int i, end;
1935 fprintf( sfd, "LangName: %d", ln->lang );
1936 for ( end = ttf_namemax; end>0 && ln->names[end-1]==NULL; --end );
1937 for ( i=0; i<end; ++i ) {
1938 putc(' ',sfd);
1939 SFDDumpUTF7Str(sfd,ln->names[i]);
1940 }
1941 putc('\n',sfd);
1942 }
1943
SFDDumpGasp(FILE * sfd,SplineFont * sf)1944 static void SFDDumpGasp(FILE *sfd, SplineFont *sf) {
1945 int i;
1946
1947 if ( sf->gasp_cnt==0 )
1948 return;
1949
1950 fprintf( sfd, "GaspTable: %d", sf->gasp_cnt );
1951 for ( i=0; i<sf->gasp_cnt; ++i )
1952 fprintf( sfd, " %d %d", sf->gasp[i].ppem, sf->gasp[i].flags );
1953 fprintf( sfd, " %d", sf->gasp_version);
1954 putc('\n',sfd);
1955 }
1956
SFDDumpDesignSize(FILE * sfd,SplineFont * sf)1957 static void SFDDumpDesignSize(FILE *sfd, SplineFont *sf) {
1958 struct otfname *on;
1959
1960 if ( sf->design_size==0 )
1961 return;
1962
1963 fprintf( sfd, "DesignSize: %d", sf->design_size );
1964 if ( sf->fontstyle_id!=0 || sf->fontstyle_name!=NULL ||
1965 sf->design_range_bottom!=0 || sf->design_range_top!=0 ) {
1966 fprintf( sfd, " %d-%d %d ",
1967 sf->design_range_bottom, sf->design_range_top,
1968 sf->fontstyle_id );
1969 for ( on=sf->fontstyle_name; on!=NULL; on=on->next ) {
1970 fprintf( sfd, "%d ", on->lang );
1971 SFDDumpUTF7Str(sfd, on->name);
1972 if ( on->next!=NULL ) putc(' ',sfd);
1973 }
1974 }
1975 putc('\n',sfd);
1976 }
1977
SFDDumpOtfFeatNames(FILE * sfd,SplineFont * sf)1978 static void SFDDumpOtfFeatNames(FILE *sfd, SplineFont *sf) {
1979 struct otffeatname *fn;
1980 struct otfname *on;
1981
1982 for ( fn=sf->feat_names; fn!=NULL; fn=fn->next ) {
1983 fprintf( sfd, "OtfFeatName: '%c%c%c%c' ",
1984 fn->tag>>24, fn->tag>>16, fn->tag>>8, fn->tag );
1985 for ( on=fn->names; on!=NULL; on=on->next ) {
1986 fprintf( sfd, "%d ", on->lang );
1987 SFDDumpUTF7Str(sfd, on->name);
1988 if ( on->next!=NULL ) putc(' ',sfd);
1989 }
1990 putc('\n',sfd);
1991 }
1992 }
1993
putstring(FILE * sfd,const char * header,char * body)1994 static void putstring(FILE *sfd, const char *header, char *body) {
1995 fprintf( sfd, "%s", header );
1996 while ( *body ) {
1997 if ( *body=='\n' || *body == '\\' || *body=='\r' ) {
1998 putc('\\',sfd);
1999 if ( *body=='\\' )
2000 putc('\\',sfd);
2001 else {
2002 putc('n',sfd);
2003 if ( *body=='\r' && body[1]=='\n' )
2004 ++body;
2005 }
2006 } else
2007 putc(*body,sfd);
2008 ++body;
2009 }
2010 putc('\n',sfd);
2011 }
2012
EncName(Encoding * encname)2013 const char *EncName(Encoding *encname) {
2014 return( encname->enc_name );
2015 }
2016
SFDDumpEncoding(FILE * sfd,Encoding * encname,const char * keyword)2017 static void SFDDumpEncoding(FILE *sfd,Encoding *encname,const char *keyword) {
2018 fprintf(sfd, "%s: %s\n", keyword, encname->enc_name );
2019 }
2020
SFDDumpMacName(FILE * sfd,struct macname * mn)2021 static void SFDDumpMacName(FILE *sfd,struct macname *mn) {
2022 char *pt;
2023
2024 while ( mn!=NULL ) {
2025 fprintf( sfd, "MacName: %d %d %d \"", mn->enc, mn->lang,
2026 (int)strlen(mn->name) );
2027 for ( pt=mn->name; *pt; ++pt ) {
2028 if ( *pt<' ' || *pt>=0x7f || *pt=='\\' || *pt=='"' )
2029 fprintf( sfd, "\\%03o", *(uint8 *) pt );
2030 else
2031 putc(*pt,sfd);
2032 }
2033 fprintf( sfd, "\"\n" );
2034 mn = mn->next;
2035 }
2036 }
2037
SFDDumpMacFeat(FILE * sfd,MacFeat * mf)2038 void SFDDumpMacFeat(FILE *sfd,MacFeat *mf) {
2039 struct macsetting *ms;
2040
2041 if ( mf==NULL )
2042 return;
2043
2044 while ( mf!=NULL ) {
2045 if ( mf->featname!=NULL ) {
2046 fprintf( sfd, "MacFeat: %d %d %d\n", mf->feature, mf->ismutex, mf->default_setting );
2047 SFDDumpMacName(sfd,mf->featname);
2048 for ( ms=mf->settings; ms!=NULL; ms=ms->next ) {
2049 if ( ms->setname!=NULL ) {
2050 fprintf( sfd, "MacSetting: %d\n", ms->setting );
2051 SFDDumpMacName(sfd,ms->setname);
2052 }
2053 }
2054 }
2055 mf = mf->next;
2056 }
2057 fprintf( sfd,"EndMacFeatures\n" );
2058 }
2059
SFDDumpBaseLang(FILE * sfd,struct baselangextent * bl)2060 static void SFDDumpBaseLang(FILE *sfd,struct baselangextent *bl) {
2061
2062 if ( bl->lang==0 )
2063 fprintf( sfd, " { %d %d", bl->descent, bl->ascent );
2064 else
2065 fprintf( sfd, " { '%c%c%c%c' %d %d",
2066 bl->lang>>24, bl->lang>>16, bl->lang>>8, bl->lang,
2067 bl->descent, bl->ascent );
2068 for ( bl=bl->features; bl!=NULL; bl=bl->next )
2069 SFDDumpBaseLang(sfd,bl);
2070 putc('}',sfd);
2071 }
2072
SFDDumpBase(FILE * sfd,const char * keyword,struct Base * base)2073 static void SFDDumpBase(FILE *sfd,const char *keyword,struct Base *base) {
2074 int i;
2075 struct basescript *bs;
2076 struct baselangextent *bl;
2077
2078 fprintf( sfd, "%s %d", keyword, base->baseline_cnt );
2079 for ( i=0; i<base->baseline_cnt; ++i ) {
2080 fprintf( sfd, " '%c%c%c%c'",
2081 base->baseline_tags[i]>>24,
2082 base->baseline_tags[i]>>16,
2083 base->baseline_tags[i]>>8,
2084 base->baseline_tags[i]);
2085 }
2086 putc('\n',sfd);
2087
2088 for ( bs=base->scripts; bs!=NULL; bs=bs->next ) {
2089 fprintf( sfd, "BaseScript: '%c%c%c%c' %d ",
2090 bs->script>>24, bs->script>>16, bs->script>>8, bs->script,
2091 bs->def_baseline );
2092 for ( i=0; i<base->baseline_cnt; ++i )
2093 fprintf( sfd, " %d", bs->baseline_pos[i]);
2094 for ( bl=bs->langs; bl!=NULL; bl=bl->next )
2095 SFDDumpBaseLang(sfd,bl);
2096 putc('\n',sfd);
2097 }
2098 }
2099
SFDDumpJSTFLookups(FILE * sfd,const char * keyword,OTLookup ** list)2100 static void SFDDumpJSTFLookups(FILE *sfd,const char *keyword, OTLookup **list ) {
2101 int i;
2102
2103 if ( list==NULL || list[0]==NULL )
2104 return;
2105
2106 fprintf( sfd, "%s ", keyword );
2107 for ( i=0; list[i]!=NULL; ++i ) {
2108 SFDDumpUTF7Str(sfd,list[i]->lookup_name);
2109 if ( list[i+1]!=NULL ) putc(' ',sfd);
2110 }
2111 putc('\n',sfd);
2112 }
2113
SFDDumpJustify(FILE * sfd,SplineFont * sf)2114 static void SFDDumpJustify(FILE *sfd,SplineFont *sf) {
2115 Justify *jscript;
2116 struct jstf_lang *jlang;
2117 int i;
2118
2119 for ( jscript = sf->justify; jscript!=NULL; jscript=jscript->next ) {
2120 fprintf( sfd, "Justify: '%c%c%c%c'\n",
2121 jscript->script>>24,
2122 jscript->script>>16,
2123 jscript->script>>8,
2124 jscript->script);
2125 if ( jscript->extenders!=NULL )
2126 fprintf( sfd, "JstfExtender: %s\n", jscript->extenders );
2127 for ( jlang = jscript->langs; jlang!=NULL; jlang = jlang->next ) {
2128 fprintf( sfd, "JstfLang: '%c%c%c%c' %d\n",
2129 jlang->lang>>24,
2130 jlang->lang>>16,
2131 jlang->lang>>8,
2132 jlang->lang, jlang->cnt );
2133 for ( i=0; i<jlang->cnt; ++i ) {
2134 fprintf( sfd, "JstfPrio:\n" );
2135 SFDDumpJSTFLookups(sfd,"JstfEnableShrink:", jlang->prios[i].enableShrink );
2136 SFDDumpJSTFLookups(sfd,"JstfDisableShrink:", jlang->prios[i].disableShrink );
2137 SFDDumpJSTFLookups(sfd,"JstfMaxShrink:", jlang->prios[i].maxShrink );
2138 SFDDumpJSTFLookups(sfd,"JstfEnableExtend:", jlang->prios[i].enableExtend );
2139 SFDDumpJSTFLookups(sfd,"JstfDisableExtend:", jlang->prios[i].disableExtend );
2140 SFDDumpJSTFLookups(sfd,"JstfMaxExtend:", jlang->prios[i].maxExtend );
2141 }
2142 }
2143 }
2144 if ( sf->justify!=NULL )
2145 fprintf( sfd, "EndJustify\n" );
2146 }
2147
SFDFpstClassNamesOut(FILE * sfd,int class_cnt,char ** classnames,const char * keyword)2148 static void SFDFpstClassNamesOut(FILE *sfd,int class_cnt,char **classnames,const char *keyword) {
2149 char buffer[20];
2150 int i;
2151
2152 if ( class_cnt>0 && classnames!=NULL ) {
2153 fprintf( sfd, " %s: ", keyword );
2154 for ( i=0; i<class_cnt; ++i ) {
2155 if ( classnames[i]==NULL ) {
2156 sprintf( buffer,"%d", i );
2157 SFDDumpUTF7Str(sfd,buffer);
2158 } else
2159 SFDDumpUTF7Str(sfd,classnames[i]);
2160 if ( i<class_cnt-1 ) putc(' ',sfd);
2161 }
2162 putc('\n',sfd);
2163 }
2164 }
2165
MakeTemporaryFile(void)2166 FILE* MakeTemporaryFile(void) {
2167 FILE *ret = NULL;
2168
2169 #ifndef __MINGW32__
2170 gchar *loc;
2171 int fd = g_file_open_tmp("fontforge-XXXXXX", &loc, NULL);
2172
2173 if (fd != -1) {
2174 ret = fdopen(fd, "w+");
2175 g_unlink(loc);
2176 g_free(loc);
2177 }
2178 #else
2179 HANDLE hFile = INVALID_HANDLE_VALUE;
2180 for (int retries = 0; hFile == INVALID_HANDLE_VALUE && retries < 10; retries++) {
2181 wchar_t *temp = _wtempnam(NULL, L"FontForge");
2182 hFile = CreateFileW(temp, GENERIC_READ|GENERIC_WRITE, 0, NULL,
2183 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL);
2184 free(temp);
2185 }
2186 ret = _fdopen(_open_osfhandle((intptr_t)hFile, 0), "wb+");
2187 if (ret == NULL && hFile != INVALID_HANDLE_VALUE) {
2188 CloseHandle(hFile);
2189 }
2190 #endif
2191 return ret;
2192 }
2193
2194
2195 /**
2196 * Read an entire file from the given open file handle and return that data
2197 * as an allocated string that the caller must free.
2198 * If any read or memory error occurs, then free string and return 0.
2199 * FIXME: Use a better method than fseek() and ftell() since this does not
2200 * play well with stdin, streaming input type files, or files with NULLs
2201 */
FileToAllocatedString(FILE * f)2202 char* FileToAllocatedString( FILE *f ) {
2203 char *ret, *buf;
2204 long fsize = 0;
2205 size_t bread = 0;
2206
2207 /* get approximate file size, and allocate some memory */
2208 if ( fseek(f,0,SEEK_END)==0 && \
2209 (fsize=ftell(f))!=-1 && \
2210 fseek(f,0,SEEK_SET)==0 && \
2211 (buf=calloc(fsize+30001,1))!=NULL ) {
2212 /* fread in file, size=non-exact, then resize memory smaller */
2213 bread=fread(buf,1,fsize+30000,f);
2214 if ( bread<=0 || bread >=(size_t)fsize+30000 || (ret=realloc(buf,bread+1))==NULL ) {
2215 free( buf );
2216 } else {
2217 ret[bread] = '\0';
2218 return( ret );
2219 }
2220 }
2221
2222 /* error occurred reading in file */
2223 fprintf(stderr,_("Failed to read a file. Bytes read:%ld file size:%ld\n"),(long)(bread),fsize );
2224 return( 0 );
2225 }
2226
2227
SFD_DumpLookup(FILE * sfd,SplineFont * sf)2228 void SFD_DumpLookup( FILE *sfd, SplineFont *sf ) {
2229 int isgpos;
2230 OTLookup *otl;
2231 struct lookup_subtable *sub;
2232 FeatureScriptLangList *fl;
2233 struct scriptlanglist *sl;
2234 int i;
2235
2236 for ( isgpos=0; isgpos<2; ++isgpos ) {
2237 for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl = otl->next ) {
2238 fprintf( sfd, "Lookup: %d %d %d ", otl->lookup_type, otl->lookup_flags, otl->store_in_afm );
2239 SFDDumpUTF7Str(sfd,otl->lookup_name);
2240 fprintf( sfd, " { " );
2241 for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
2242 SFDDumpUTF7Str(sfd,sub->subtable_name);
2243 putc(' ',sfd);
2244 if ( otl->lookup_type==gsub_single && sub->suffix!=NULL ) {
2245 putc('(',sfd);
2246 SFDDumpUTF7Str(sfd,sub->suffix);
2247 putc(')',sfd);
2248 } else if ( otl->lookup_type==gpos_pair && sub->vertical_kerning )
2249 fprintf(sfd,"(1)");
2250 if ( otl->lookup_type==gpos_pair && (sub->separation!=0 || sub->kerning_by_touch))
2251 fprintf(sfd,"[%d,%d,%d]", sub->separation, sub->minkern, sub->kerning_by_touch+2*sub->onlyCloser+4*sub->dontautokern );
2252 putc(' ',sfd);
2253 }
2254 fprintf( sfd, "} [" );
2255 for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
2256 if ( fl->ismac )
2257 fprintf( sfd, "<%d,%d> (",
2258 (int) (fl->featuretag>>16),
2259 (int) (fl->featuretag&0xffff));
2260 else
2261 fprintf( sfd, "'%c%c%c%c' (",
2262 (int) (fl->featuretag>>24), (int) ((fl->featuretag>>16)&0xff),
2263 (int) ((fl->featuretag>>8)&0xff), (int) (fl->featuretag&0xff) );
2264 for ( sl= fl->scripts; sl!=NULL; sl = sl->next ) {
2265 fprintf( sfd, "'%c%c%c%c' <",
2266 (int) (sl->script>>24), (int) ((sl->script>>16)&0xff),
2267 (int) ((sl->script>>8)&0xff), (int) (sl->script&0xff) );
2268 for ( i=0; i<sl->lang_cnt; ++i ) {
2269 uint32 lang = i<MAX_LANG ? sl->langs[i] : sl->morelangs[i-MAX_LANG];
2270 fprintf( sfd, "'%c%c%c%c' ",
2271 (int) (lang>>24), (int) ((lang>>16)&0xff),
2272 (int) ((lang>>8)&0xff), (int) (lang&0xff) );
2273 }
2274 fprintf( sfd, "> " );
2275 }
2276 fprintf( sfd, ") " );
2277 }
2278 fprintf( sfd, "]\n" );
2279 }
2280 }
2281 }
2282
SFD_DumpSplineFontMetadata(FILE * sfd,SplineFont * sf)2283 int SFD_DumpSplineFontMetadata( FILE *sfd, SplineFont *sf )
2284 {
2285 int i, j;
2286 struct ttflangname *ln;
2287 struct ttf_table *tab;
2288 KernClass *kc;
2289 FPST *fpst;
2290 ASM *sm;
2291 int isv;
2292 int err = false;
2293 int isgpos;
2294 OTLookup *otl;
2295 struct lookup_subtable *sub;
2296 FeatureScriptLangList *fl;
2297 struct scriptlanglist *sl;
2298
2299 fprintf(sfd, "FontName: %s\n", sf->fontname );
2300 if ( sf->fullname!=NULL )
2301 fprintf(sfd, "FullName: %s\n", sf->fullname );
2302 if ( sf->familyname!=NULL )
2303 fprintf(sfd, "FamilyName: %s\n", sf->familyname );
2304 if ( sf->weight!=NULL )
2305 fprintf(sfd, "Weight: %s\n", sf->weight );
2306 if ( sf->copyright!=NULL )
2307 putstring(sfd, "Copyright: ", sf->copyright );
2308 if ( sf->comments!=NULL ) {
2309 fprintf( sfd, "UComments: " );
2310 SFDDumpUTF7Str(sfd,sf->comments);
2311 putc('\n',sfd);
2312 }
2313 if ( sf->fontlog!=NULL ) {
2314 fprintf( sfd, "FontLog: " );
2315 SFDDumpUTF7Str(sfd,sf->fontlog);
2316 putc('\n',sfd);
2317 }
2318
2319 if ( sf->version!=NULL )
2320 fprintf(sfd, "Version: %s\n", sf->version );
2321 if ( sf->styleMapFamilyName!=NULL )
2322 fprintf(sfd, "StyleMapFamilyName: %s\n", sf->styleMapFamilyName );
2323 if ( sf->fondname!=NULL )
2324 fprintf(sfd, "FONDName: %s\n", sf->fondname );
2325 if ( sf->defbasefilename!=NULL )
2326 fprintf(sfd, "DefaultBaseFilename: %s\n", sf->defbasefilename );
2327 if ( sf->strokewidth!=0 )
2328 fprintf(sfd, "StrokeWidth: %g\n", (double) sf->strokewidth );
2329 fprintf(sfd, "ItalicAngle: %g\n", (double) sf->italicangle );
2330 fprintf(sfd, "UnderlinePosition: %g\n", (double) sf->upos );
2331 fprintf(sfd, "UnderlineWidth: %g\n", (double) sf->uwidth );
2332 fprintf(sfd, "Ascent: %d\n", sf->ascent );
2333 fprintf(sfd, "Descent: %d\n", sf->descent );
2334 fprintf(sfd, "InvalidEm: %d\n", sf->invalidem );
2335 if ( sf->sfntRevision!=sfntRevisionUnset )
2336 fprintf(sfd, "sfntRevision: 0x%08x\n", sf->sfntRevision );
2337 if ( sf->woffMajor!=woffUnset ) {
2338 fprintf(sfd, "woffMajor: %d\n", sf->woffMajor );
2339 fprintf(sfd, "woffMinor: %d\n", sf->woffMinor );
2340 }
2341 if ( sf->woffMetadata!=NULL ) {
2342 fprintf( sfd, "woffMetadata: " );
2343 SFDDumpUTF7Str(sfd,sf->woffMetadata);
2344 putc('\n',sfd);
2345 }
2346 if ( sf->ufo_ascent!=0 )
2347 fprintf(sfd, "UFOAscent: %g\n", (double) sf->ufo_ascent );
2348 if ( sf->ufo_descent!=0 )
2349 fprintf(sfd, "UFODescent: %g\n", (double) sf->ufo_descent );
2350 fprintf(sfd, "LayerCount: %d\n", sf->layer_cnt );
2351 for ( i=0; i<sf->layer_cnt; ++i ) {
2352 fprintf( sfd, "Layer: %d %d ", i, sf->layers[i].order2/*, sf->layers[i].background*/ );
2353 SFDDumpUTF7Str(sfd,sf->layers[i].name);
2354 fprintf( sfd, " %d", sf->layers[i].background );
2355 if (sf->layers[i].ufo_path != NULL) { putc(' ',sfd); SFDDumpUTF7Str(sfd,sf->layers[i].ufo_path); }
2356 putc('\n',sfd);
2357 }
2358 // TODO: Output U. F. O. layer path.
2359 if (sf->preferred_kerning != 0) fprintf(sfd, "PreferredKerning: %d\n", sf->preferred_kerning);
2360 if ( sf->strokedfont )
2361 fprintf(sfd, "StrokedFont: %d\n", sf->strokedfont );
2362 else if ( sf->multilayer )
2363 fprintf(sfd, "MultiLayer: %d\n", sf->multilayer );
2364 if ( sf->hasvmetrics )
2365 fprintf(sfd, "HasVMetrics: %d\n", sf->hasvmetrics );
2366 if ( sf->use_xuid && sf->changed_since_xuidchanged )
2367 fprintf(sfd, "NeedsXUIDChange: 1\n" );
2368 if ( sf->xuid!=NULL )
2369 fprintf(sfd, "XUID: %s\n", sf->xuid );
2370 if ( sf->uniqueid!=0 )
2371 fprintf(sfd, "UniqueID: %d\n", sf->uniqueid );
2372 if ( sf->use_xuid )
2373 fprintf(sfd, "UseXUID: 1\n" );
2374 if ( sf->use_uniqueid )
2375 fprintf(sfd, "UseUniqueID: 1\n" );
2376 if ( sf->horiz_base!=NULL )
2377 SFDDumpBase(sfd,"BaseHoriz:",sf->horiz_base);
2378 if ( sf->vert_base!=NULL )
2379 SFDDumpBase(sfd,"BaseVert:",sf->vert_base);
2380 if ( sf->pfminfo.stylemap!=-1 )
2381 fprintf(sfd, "StyleMap: 0x%04x\n", sf->pfminfo.stylemap );
2382 if ( sf->pfminfo.fstype!=-1 )
2383 fprintf(sfd, "FSType: %d\n", sf->pfminfo.fstype );
2384 fprintf(sfd, "OS2Version: %d\n", sf->os2_version );
2385 fprintf(sfd, "OS2_WeightWidthSlopeOnly: %d\n", sf->weight_width_slope_only );
2386 fprintf(sfd, "OS2_UseTypoMetrics: %d\n", sf->use_typo_metrics );
2387 fprintf(sfd, "CreationTime: %lld\n", sf->creationtime );
2388 fprintf(sfd, "ModificationTime: %lld\n", sf->modificationtime );
2389 if ( sf->pfminfo.pfmset ) {
2390 fprintf(sfd, "PfmFamily: %d\n", sf->pfminfo.pfmfamily );
2391 fprintf(sfd, "TTFWeight: %d\n", sf->pfminfo.weight );
2392 fprintf(sfd, "TTFWidth: %d\n", sf->pfminfo.width );
2393 fprintf(sfd, "LineGap: %d\n", sf->pfminfo.linegap );
2394 fprintf(sfd, "VLineGap: %d\n", sf->pfminfo.vlinegap );
2395 /*putc('\n',sfd);*/
2396 }
2397 if ( sf->pfminfo.panose_set ) {
2398 fprintf(sfd, "Panose:" );
2399 for ( i=0; i<10; ++i )
2400 fprintf( sfd, " %d", sf->pfminfo.panose[i]);
2401 putc('\n',sfd);
2402 }
2403 fprintf(sfd, "OS2TypoAscent: %d\n", sf->pfminfo.os2_typoascent );
2404 fprintf(sfd, "OS2TypoAOffset: %d\n", sf->pfminfo.typoascent_add );
2405 fprintf(sfd, "OS2TypoDescent: %d\n", sf->pfminfo.os2_typodescent );
2406 fprintf(sfd, "OS2TypoDOffset: %d\n", sf->pfminfo.typodescent_add );
2407 fprintf(sfd, "OS2TypoLinegap: %d\n", sf->pfminfo.os2_typolinegap );
2408 fprintf(sfd, "OS2WinAscent: %d\n", sf->pfminfo.os2_winascent );
2409 fprintf(sfd, "OS2WinAOffset: %d\n", sf->pfminfo.winascent_add );
2410 fprintf(sfd, "OS2WinDescent: %d\n", sf->pfminfo.os2_windescent );
2411 fprintf(sfd, "OS2WinDOffset: %d\n", sf->pfminfo.windescent_add );
2412 fprintf(sfd, "HheadAscent: %d\n", sf->pfminfo.hhead_ascent );
2413 fprintf(sfd, "HheadAOffset: %d\n", sf->pfminfo.hheadascent_add );
2414 fprintf(sfd, "HheadDescent: %d\n", sf->pfminfo.hhead_descent );
2415 fprintf(sfd, "HheadDOffset: %d\n", sf->pfminfo.hheaddescent_add );
2416 if ( sf->pfminfo.subsuper_set ) {
2417 fprintf(sfd, "OS2SubXSize: %d\n", sf->pfminfo.os2_subxsize );
2418 fprintf(sfd, "OS2SubYSize: %d\n", sf->pfminfo.os2_subysize );
2419 fprintf(sfd, "OS2SubXOff: %d\n", sf->pfminfo.os2_subxoff );
2420 fprintf(sfd, "OS2SubYOff: %d\n", sf->pfminfo.os2_subyoff );
2421 fprintf(sfd, "OS2SupXSize: %d\n", sf->pfminfo.os2_supxsize );
2422 fprintf(sfd, "OS2SupYSize: %d\n", sf->pfminfo.os2_supysize );
2423 fprintf(sfd, "OS2SupXOff: %d\n", sf->pfminfo.os2_supxoff );
2424 fprintf(sfd, "OS2SupYOff: %d\n", sf->pfminfo.os2_supyoff );
2425 fprintf(sfd, "OS2StrikeYSize: %d\n", sf->pfminfo.os2_strikeysize );
2426 fprintf(sfd, "OS2StrikeYPos: %d\n", sf->pfminfo.os2_strikeypos );
2427 }
2428 if ( sf->pfminfo.os2_capheight!=0 )
2429 fprintf(sfd, "OS2CapHeight: %d\n", sf->pfminfo.os2_capheight );
2430 if ( sf->pfminfo.os2_xheight!=0 )
2431 fprintf(sfd, "OS2XHeight: %d\n", sf->pfminfo.os2_xheight );
2432 if ( sf->pfminfo.os2_family_class!=0 )
2433 fprintf(sfd, "OS2FamilyClass: %d\n", sf->pfminfo.os2_family_class );
2434 if ( sf->pfminfo.os2_vendor[0]!='\0' ) {
2435 fprintf(sfd, "OS2Vendor: '%c%c%c%c'\n",
2436 sf->pfminfo.os2_vendor[0], sf->pfminfo.os2_vendor[1],
2437 sf->pfminfo.os2_vendor[2], sf->pfminfo.os2_vendor[3] );
2438 }
2439 if ( sf->pfminfo.hascodepages )
2440 fprintf(sfd, "OS2CodePages: %08x.%08x\n", sf->pfminfo.codepages[0], sf->pfminfo.codepages[1]);
2441 if ( sf->pfminfo.hasunicoderanges )
2442 fprintf(sfd, "OS2UnicodeRanges: %08x.%08x.%08x.%08x\n",
2443 sf->pfminfo.unicoderanges[0], sf->pfminfo.unicoderanges[1],
2444 sf->pfminfo.unicoderanges[2], sf->pfminfo.unicoderanges[3] );
2445 if ( sf->macstyle!=-1 )
2446 fprintf(sfd, "MacStyle: %d\n", sf->macstyle );
2447 /* Must come before any kerning classes, anchor classes, conditional psts */
2448 /* state machines, psts, kerning pairs, etc. */
2449 for ( isgpos=0; isgpos<2; ++isgpos ) {
2450 for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl = otl->next ) {
2451 fprintf( sfd, "Lookup: %d %d %d ", otl->lookup_type, otl->lookup_flags, otl->store_in_afm );
2452 SFDDumpUTF7Str(sfd,otl->lookup_name);
2453 fprintf( sfd, " { " );
2454 for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
2455 SFDDumpUTF7Str(sfd,sub->subtable_name);
2456 putc(' ',sfd);
2457 if ( otl->lookup_type==gsub_single && sub->suffix!=NULL ) {
2458 putc('(',sfd);
2459 SFDDumpUTF7Str(sfd,sub->suffix);
2460 putc(')',sfd);
2461 } else if ( otl->lookup_type==gpos_pair && sub->vertical_kerning )
2462 fprintf(sfd,"(1)");
2463 if ( otl->lookup_type==gpos_pair && (sub->separation!=0 || sub->kerning_by_touch))
2464 fprintf(sfd,"[%d,%d,%d]", sub->separation, sub->minkern, sub->kerning_by_touch+2*sub->onlyCloser+4*sub->dontautokern );
2465 putc(' ',sfd);
2466 }
2467 fprintf( sfd, "} [" );
2468 for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
2469 if ( fl->ismac )
2470 fprintf( sfd, "<%d,%d> (",
2471 (int) (fl->featuretag>>16),
2472 (int) (fl->featuretag&0xffff));
2473 else
2474 fprintf( sfd, "'%c%c%c%c' (",
2475 (int) (fl->featuretag>>24), (int) ((fl->featuretag>>16)&0xff),
2476 (int) ((fl->featuretag>>8)&0xff), (int) (fl->featuretag&0xff) );
2477 for ( sl= fl->scripts; sl!=NULL; sl = sl->next ) {
2478 fprintf( sfd, "'%c%c%c%c' <",
2479 (int) (sl->script>>24), (int) ((sl->script>>16)&0xff),
2480 (int) ((sl->script>>8)&0xff), (int) (sl->script&0xff) );
2481 for ( i=0; i<sl->lang_cnt; ++i ) {
2482 uint32 lang = i<MAX_LANG ? sl->langs[i] : sl->morelangs[i-MAX_LANG];
2483 fprintf( sfd, "'%c%c%c%c' ",
2484 (int) (lang>>24), (int) ((lang>>16)&0xff),
2485 (int) ((lang>>8)&0xff), (int) (lang&0xff) );
2486 }
2487 fprintf( sfd, "> " );
2488 }
2489 fprintf( sfd, ") " );
2490 }
2491 fprintf( sfd, "]\n" );
2492 }
2493 }
2494
2495 if ( sf->mark_class_cnt!=0 ) {
2496 fprintf( sfd, "MarkAttachClasses: %d\n", sf->mark_class_cnt );
2497 for ( i=1; i<sf->mark_class_cnt; ++i ) { /* Class 0 is unused */
2498 SFDDumpUTF7Str(sfd, sf->mark_class_names[i]);
2499 putc(' ',sfd);
2500 if ( sf->mark_classes[i]!=NULL )
2501 fprintf( sfd, "%d %s\n", (int) strlen(sf->mark_classes[i]),
2502 sf->mark_classes[i] );
2503 else
2504 fprintf( sfd, "0 \n" );
2505 }
2506 }
2507 if ( sf->mark_set_cnt!=0 ) {
2508 fprintf( sfd, "MarkAttachSets: %d\n", sf->mark_set_cnt );
2509 for ( i=0; i<sf->mark_set_cnt; ++i ) { /* Set 0 is used */
2510 SFDDumpUTF7Str(sfd, sf->mark_set_names[i]);
2511 putc(' ',sfd);
2512 if ( sf->mark_sets[i]!=NULL )
2513 fprintf( sfd, "%d %s\n", (int) strlen(sf->mark_sets[i]),
2514 sf->mark_sets[i] );
2515 else
2516 fprintf( sfd, "0 \n" );
2517 }
2518 }
2519
2520 fprintf( sfd, "DEI: 91125\n" );
2521 for ( isv=0; isv<2; ++isv ) {
2522 for ( kc=isv ? sf->vkerns : sf->kerns; kc!=NULL; kc = kc->next ) {
2523 if (kc->firsts_names == NULL && kc->seconds_names == NULL && kc->firsts_flags == NULL && kc->seconds_flags == NULL) {
2524 fprintf( sfd, "%s: %d%s %d ", isv ? "VKernClass2" : "KernClass2",
2525 kc->first_cnt, kc->firsts[0]!=NULL?"+":"",
2526 kc->second_cnt );
2527 SFDDumpUTF7Str(sfd,kc->subtable->subtable_name);
2528 putc('\n',sfd);
2529 if ( kc->firsts[0]!=NULL )
2530 fprintf( sfd, " %d %s\n", (int)strlen(kc->firsts[0]),
2531 kc->firsts[0]);
2532 for ( i=1; i<kc->first_cnt; ++i )
2533 fprintf( sfd, " %d %s\n", (int)strlen(kc->firsts[i]),
2534 kc->firsts[i]);
2535 for ( i=1; i<kc->second_cnt; ++i )
2536 fprintf( sfd, " %d %s\n", (int)strlen(kc->seconds[i]),
2537 kc->seconds[i]);
2538 for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
2539 fprintf( sfd, " %d", kc->offsets[i]);
2540 putc(' ',sfd);
2541 SFDDumpDeviceTable(sfd,&kc->adjusts[i]);
2542 }
2543 fprintf( sfd, "\n" );
2544 } else {
2545 fprintf( sfd, "%s: %d%s %d ", isv ? "VKernClass3" : "KernClass3",
2546 kc->first_cnt, kc->firsts[0]!=NULL?"+":"",
2547 kc->second_cnt );
2548 SFDDumpUTF7Str(sfd,kc->subtable->subtable_name);
2549 putc('\n',sfd);
2550 if ( kc->firsts[0]!=NULL ) {
2551 fprintf( sfd, " %d ", ((kc->firsts_flags && kc->firsts_flags[0]) ? kc->firsts_flags[0] : 0));
2552 SFDDumpUTF7Str(sfd, ((kc->firsts_names && kc->firsts_names[0]) ? kc->firsts_names[0] : ""));
2553 fprintf( sfd, " " );
2554 SFDDumpUTF7Str(sfd,kc->firsts[0]);
2555 fprintf( sfd, "\n" );
2556 }
2557 for ( i=1; i<kc->first_cnt; ++i ) {
2558 fprintf( sfd, " %d ", ((kc->firsts_flags && kc->firsts_flags[i]) ? kc->firsts_flags[i] : 0));
2559 SFDDumpUTF7Str(sfd, ((kc->firsts_names && kc->firsts_names[i]) ? kc->firsts_names[i] : ""));
2560 fprintf( sfd, " " );
2561 SFDDumpUTF7Str(sfd,kc->firsts[i]);
2562 fprintf( sfd, "\n" );
2563 }
2564 for ( i=1; i<kc->second_cnt; ++i ) {
2565 fprintf( sfd, " %d ", ((kc->seconds_flags && kc->seconds_flags[i]) ? kc->seconds_flags[i] : 0));
2566 SFDDumpUTF7Str(sfd, ((kc->seconds_names && kc->seconds_names[i]) ? kc->seconds_names[i] : ""));
2567 fprintf( sfd, " " );
2568 SFDDumpUTF7Str(sfd,kc->seconds[i]);
2569 fprintf( sfd, "\n" );
2570 }
2571 for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
2572 fprintf( sfd, " %d %d", ((kc->offsets_flags && kc->offsets_flags[i]) ? kc->offsets_flags[i] : 0), kc->offsets[i]);
2573 putc(' ',sfd);
2574 SFDDumpDeviceTable(sfd,&kc->adjusts[i]);
2575 }
2576 fprintf( sfd, "\n" );
2577 }
2578 }
2579 }
2580 for ( fpst=sf->possub; fpst!=NULL; fpst=fpst->next ) {
2581 static const char *keywords[] = { "ContextPos2:", "ContextSub2:", "ChainPos2:", "ChainSub2:", "ReverseChain2:", NULL };
2582 static const char *formatkeys[] = { "glyph", "class", "coverage", "revcov", NULL };
2583 fprintf( sfd, "%s %s ", keywords[fpst->type-pst_contextpos],
2584 formatkeys[fpst->format] );
2585 SFDDumpUTF7Str(sfd,fpst->subtable->subtable_name);
2586 fprintf( sfd, " %d %d %d %d\n",
2587 fpst->nccnt, fpst->bccnt, fpst->fccnt, fpst->rule_cnt );
2588 if ( fpst->nccnt>0 && fpst->nclass[0]!=NULL )
2589 fprintf( sfd, " Class0: %d %s\n", (int)strlen(fpst->nclass[0]),
2590 fpst->nclass[0]);
2591 for ( i=1; i<fpst->nccnt; ++i )
2592 fprintf( sfd, " Class: %d %s\n", (int)strlen(fpst->nclass[i]),
2593 fpst->nclass[i]);
2594 for ( i=1; i<fpst->bccnt; ++i )
2595 fprintf( sfd, " BClass: %d %s\n", (int)strlen(fpst->bclass[i]),
2596 fpst->bclass[i]);
2597 for ( i=1; i<fpst->fccnt; ++i )
2598 fprintf( sfd, " FClass: %d %s\n", (int)strlen(fpst->fclass[i]),
2599 fpst->fclass[i]);
2600 for ( i=0; i<fpst->rule_cnt; ++i ) {
2601 switch ( fpst->format ) {
2602 case pst_glyphs:
2603 fprintf( sfd, " String: %d %s\n",
2604 (int)strlen(fpst->rules[i].u.glyph.names),
2605 fpst->rules[i].u.glyph.names);
2606 if ( fpst->rules[i].u.glyph.back!=NULL )
2607 fprintf( sfd, " BString: %d %s\n",
2608 (int)strlen(fpst->rules[i].u.glyph.back),
2609 fpst->rules[i].u.glyph.back);
2610 else
2611 fprintf( sfd, " BString: 0\n");
2612 if ( fpst->rules[i].u.glyph.fore!=NULL )
2613 fprintf( sfd, " FString: %d %s\n",
2614 (int)strlen(fpst->rules[i].u.glyph.fore),
2615 fpst->rules[i].u.glyph.fore);
2616 else
2617 fprintf( sfd, " FString: 0\n");
2618 break;
2619 case pst_class:
2620 fprintf( sfd, " %d %d %d\n ClsList:", fpst->rules[i].u.class.ncnt, fpst->rules[i].u.class.bcnt, fpst->rules[i].u.class.fcnt );
2621 for ( j=0; j<fpst->rules[i].u.class.ncnt; ++j )
2622 fprintf( sfd, " %d", fpst->rules[i].u.class.nclasses[j]);
2623 fprintf( sfd, "\n BClsList:" );
2624 for ( j=0; j<fpst->rules[i].u.class.bcnt; ++j )
2625 fprintf( sfd, " %d", fpst->rules[i].u.class.bclasses[j]);
2626 fprintf( sfd, "\n FClsList:" );
2627 for ( j=0; j<fpst->rules[i].u.class.fcnt; ++j )
2628 fprintf( sfd, " %d", fpst->rules[i].u.class.fclasses[j]);
2629 fprintf( sfd, "\n" );
2630 break;
2631 case pst_coverage:
2632 case pst_reversecoverage:
2633 fprintf( sfd, " %d %d %d\n", fpst->rules[i].u.coverage.ncnt, fpst->rules[i].u.coverage.bcnt, fpst->rules[i].u.coverage.fcnt );
2634 for ( j=0; j<fpst->rules[i].u.coverage.ncnt; ++j )
2635 fprintf( sfd, " Coverage: %d %s\n",
2636 (int)strlen(fpst->rules[i].u.coverage.ncovers[j]),
2637 fpst->rules[i].u.coverage.ncovers[j]);
2638 for ( j=0; j<fpst->rules[i].u.coverage.bcnt; ++j )
2639 fprintf( sfd, " BCoverage: %d %s\n",
2640 (int)strlen(fpst->rules[i].u.coverage.bcovers[j]),
2641 fpst->rules[i].u.coverage.bcovers[j]);
2642 for ( j=0; j<fpst->rules[i].u.coverage.fcnt; ++j )
2643 fprintf( sfd, " FCoverage: %d %s\n",
2644 (int)strlen(fpst->rules[i].u.coverage.fcovers[j]),
2645 fpst->rules[i].u.coverage.fcovers[j]);
2646 break;
2647 default:
2648 break;
2649 }
2650 switch ( fpst->format ) {
2651 case pst_glyphs:
2652 case pst_class:
2653 case pst_coverage:
2654 fprintf( sfd, " %d\n", fpst->rules[i].lookup_cnt );
2655 for ( j=0; j<fpst->rules[i].lookup_cnt; ++j ) {
2656 fprintf( sfd, " SeqLookup: %d ",
2657 fpst->rules[i].lookups[j].seq );
2658 SFDDumpUTF7Str(sfd,fpst->rules[i].lookups[j].lookup->lookup_name);
2659 putc('\n',sfd);
2660 }
2661 break;
2662 case pst_reversecoverage:
2663 fprintf( sfd, " Replace: %d %s\n",
2664 (int)strlen(fpst->rules[i].u.rcoverage.replacements),
2665 fpst->rules[i].u.rcoverage.replacements);
2666 break;
2667 default:
2668 break;
2669 }
2670 }
2671 /* It would make more sense to output these up near the classes */
2672 /* but that would break backwards compatibility (old parsers will */
2673 /* ignore these entries if they are at the end, new parsers will */
2674 /* read them */
2675 SFDFpstClassNamesOut(sfd,fpst->nccnt,fpst->nclassnames,"ClassNames");
2676 SFDFpstClassNamesOut(sfd,fpst->bccnt,fpst->bclassnames,"BClassNames");
2677 SFDFpstClassNamesOut(sfd,fpst->fccnt,fpst->fclassnames,"FClassNames");
2678 fprintf( sfd, "EndFPST\n" );
2679 }
2680 struct ff_glyphclasses *grouptmp;
2681 for ( grouptmp = sf->groups; grouptmp != NULL; grouptmp = grouptmp->next ) {
2682 fprintf(sfd, "Group: ");
2683 SFDDumpUTF7Str(sfd, grouptmp->classname); fprintf(sfd, " ");
2684 SFDDumpUTF7Str(sfd, grouptmp->glyphs); fprintf(sfd, "\n");
2685 }
2686 struct ff_rawoffsets *groupkerntmp;
2687 for ( groupkerntmp = sf->groupkerns; groupkerntmp != NULL; groupkerntmp = groupkerntmp->next ) {
2688 fprintf(sfd, "GroupKern: ");
2689 SFDDumpUTF7Str(sfd, groupkerntmp->left); fprintf(sfd, " ");
2690 SFDDumpUTF7Str(sfd, groupkerntmp->right); fprintf(sfd, " ");
2691 fprintf(sfd, "%d\n", groupkerntmp->offset);
2692 }
2693 for ( groupkerntmp = sf->groupvkerns; groupkerntmp != NULL; groupkerntmp = groupkerntmp->next ) {
2694 fprintf(sfd, "GroupVKern: ");
2695 SFDDumpUTF7Str(sfd, groupkerntmp->left); fprintf(sfd, " ");
2696 SFDDumpUTF7Str(sfd, groupkerntmp->right); fprintf(sfd, " ");
2697 fprintf(sfd, "%d\n", groupkerntmp->offset);
2698 }
2699 for ( sm=sf->sm; sm!=NULL; sm=sm->next ) {
2700 static const char *keywords[] = { "MacIndic2:", "MacContext2:", "MacLigature2:", "unused", "MacSimple2:", "MacInsert2:",
2701 "unused", "unused", "unused", "unused", "unused", "unused",
2702 "unused", "unused", "unused", "unused", "unused", "MacKern2:",
2703 NULL };
2704 fprintf( sfd, "%s ", keywords[sm->type-asm_indic] );
2705 SFDDumpUTF7Str(sfd,sm->subtable->subtable_name);
2706 fprintf( sfd, " %d %d %d\n", sm->flags, sm->class_cnt, sm->state_cnt );
2707 for ( i=4; i<sm->class_cnt; ++i )
2708 fprintf( sfd, " Class: %d %s\n", (int)strlen(sm->classes[i]),
2709 sm->classes[i]);
2710 for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
2711 fprintf( sfd, " %d %d ", sm->state[i].next_state, sm->state[i].flags );
2712 if ( sm->type==asm_context ) {
2713 if ( sm->state[i].u.context.mark_lookup==NULL )
2714 putc('~',sfd);
2715 else
2716 SFDDumpUTF7Str(sfd,sm->state[i].u.context.mark_lookup->lookup_name);
2717 putc(' ',sfd);
2718 if ( sm->state[i].u.context.cur_lookup==0 )
2719 putc('~',sfd);
2720 else
2721 SFDDumpUTF7Str(sfd,sm->state[i].u.context.cur_lookup->lookup_name);
2722 putc(' ',sfd);
2723 } else if ( sm->type == asm_insert ) {
2724 if ( sm->state[i].u.insert.mark_ins==NULL )
2725 fprintf( sfd, "0 ");
2726 else
2727 fprintf( sfd, "%d %s ",
2728 (int)strlen(sm->state[i].u.insert.mark_ins),
2729 sm->state[i].u.insert.mark_ins );
2730 if ( sm->state[i].u.insert.cur_ins==NULL )
2731 fprintf( sfd, "0 ");
2732 else
2733 fprintf( sfd, "%d %s ",
2734 (int)strlen(sm->state[i].u.insert.cur_ins),
2735 sm->state[i].u.insert.cur_ins );
2736 } else if ( sm->type == asm_kern ) {
2737 fprintf( sfd, "%d ", sm->state[i].u.kern.kcnt );
2738 for ( j=0; j<sm->state[i].u.kern.kcnt; ++j )
2739 fprintf( sfd, "%d ", sm->state[i].u.kern.kerns[j]);
2740 }
2741 putc('\n',sfd);
2742 }
2743 fprintf( sfd, "EndASM\n" );
2744 }
2745 SFDDumpMacFeat(sfd,sf->features);
2746 SFDDumpJustify(sfd,sf);
2747 for ( tab = sf->ttf_tables; tab!=NULL ; tab = tab->next )
2748 SFDDumpTtfTable(sfd,tab,sf);
2749 for ( tab = sf->ttf_tab_saved; tab!=NULL ; tab = tab->next )
2750 SFDDumpTtfTable(sfd,tab,sf);
2751 for ( ln = sf->names; ln!=NULL; ln=ln->next )
2752 SFDDumpLangName(sfd,ln);
2753 if ( sf->gasp_cnt!=0 )
2754 SFDDumpGasp(sfd,sf);
2755 if ( sf->design_size!=0 )
2756 SFDDumpDesignSize(sfd,sf);
2757 if ( sf->feat_names!=NULL )
2758 SFDDumpOtfFeatNames(sfd,sf);
2759
2760 return( err );
2761 }
2762
2763
SFD_Dump(FILE * sfd,SplineFont * sf,EncMap * map,EncMap * normal,int todir,char * dirname)2764 static int SFD_Dump( FILE *sfd, SplineFont *sf, EncMap *map, EncMap *normal,
2765 int todir, char *dirname)
2766 {
2767 int i, realcnt;
2768 BDFFont *bdf;
2769 int *newgids = NULL;
2770 int err = false;
2771
2772 if ( normal!=NULL )
2773 map = normal;
2774
2775 SFD_DumpSplineFontMetadata( sfd, sf ); //, map, normal, todir, dirname );
2776
2777 if ( sf->MATH!=NULL ) {
2778 struct MATH *math = sf->MATH;
2779 for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
2780 fprintf( sfd, "MATH:%s: %d", math_constants_descriptor[i].script_name,
2781 *((int16 *) (((char *) (math)) + math_constants_descriptor[i].offset)) );
2782 if ( math_constants_descriptor[i].devtab_offset>=0 ) {
2783 DeviceTable **devtab = (DeviceTable **) (((char *) (math)) + math_constants_descriptor[i].devtab_offset );
2784 putc(' ',sfd);
2785 SFDDumpDeviceTable(sfd,*devtab);
2786 }
2787 putc('\n',sfd);
2788 }
2789 }
2790 if ( sf->python_persistent!=NULL )
2791 SFDPickleMe(sfd,sf->python_persistent, sf->python_persistent_has_lists);
2792 if ( sf->subfontcnt!=0 ) {
2793 /* CID fonts have no encodings, they have registry info instead */
2794 fprintf(sfd, "Registry: %s\n", sf->cidregistry );
2795 fprintf(sfd, "Ordering: %s\n", sf->ordering );
2796 fprintf(sfd, "Supplement: %d\n", sf->supplement );
2797 fprintf(sfd, "CIDVersion: %g\n", (double) sf->cidversion ); /* This is a number whereas "version" is a string */
2798 } else
2799 SFDDumpEncoding(sfd,map->enc,"Encoding");
2800 if ( normal!=NULL )
2801 fprintf(sfd, "Compacted: 1\n" );
2802 fprintf( sfd, "UnicodeInterp: %s\n", unicode_interp_names[sf->uni_interp]);
2803 fprintf( sfd, "NameList: %s\n", sf->for_new_glyphs->title );
2804
2805 if ( map->remap!=NULL ) {
2806 struct remap *remap;
2807 int n;
2808 for ( n=0,remap = map->remap; remap->infont!=-1; ++n, ++remap );
2809 fprintf( sfd, "RemapN: %d\n", n );
2810 for ( remap = map->remap; remap->infont!=-1; ++remap )
2811 fprintf(sfd, "Remap: %x %x %d\n", (int) remap->firstenc, (int) remap->lastenc, (int) remap->infont );
2812 }
2813 if ( sf->display_size!=0 )
2814 fprintf( sfd, "DisplaySize: %d\n", sf->display_size );
2815 if ( sf->display_layer!=ly_fore )
2816 fprintf( sfd, "DisplayLayer: %d\n", sf->display_layer );
2817 fprintf( sfd, "AntiAlias: %d\n", sf->display_antialias );
2818 fprintf( sfd, "FitToEm: %d\n", sf->display_bbsized );
2819 if ( sf->extrema_bound!=0 )
2820 fprintf( sfd, "ExtremaBound: %d\n", sf->extrema_bound );
2821 if ( sf->width_separation!=0 )
2822 fprintf( sfd, "WidthSeparation: %d\n", sf->width_separation );
2823 {
2824 int rc, cc, te;
2825 if ( (te = FVWinInfo(sf->fv,&cc,&rc))!= -1 )
2826 fprintf( sfd, "WinInfo: %d %d %d\n", te, cc, rc );
2827 else if ( sf->top_enc!=-1 )
2828 fprintf( sfd, "WinInfo: %d %d %d\n", sf->top_enc, sf->desired_col_cnt,
2829 sf->desired_row_cnt);
2830 }
2831 if ( sf->onlybitmaps!=0 )
2832 fprintf( sfd, "OnlyBitmaps: %d\n", sf->onlybitmaps );
2833 if ( sf->private!=NULL )
2834 SFDDumpPrivate(sfd,sf->private);
2835 #if HANYANG
2836 if ( sf->rules!=NULL )
2837 SFDDumpCompositionRules(sfd,sf->rules);
2838 #endif
2839 if ( sf->grid.splines!=NULL ) {
2840 if ( sf->grid.order2 )
2841 fprintf(sfd, "GridOrder2: %d\n", sf->grid.order2 );
2842 fprintf(sfd, "Grid\n" );
2843 SFDDumpSplineSet(sfd,sf->grid.splines,sf->grid.order2);
2844 }
2845 if ( sf->texdata.type!=tex_unset ) {
2846 fprintf(sfd, "TeXData: %d %d", (int) sf->texdata.type, (int) ((sf->design_size<<19)+2)/5 );
2847 for ( i=0; i<22; ++i )
2848 fprintf(sfd, " %d", (int) sf->texdata.params[i]);
2849 putc('\n',sfd);
2850 }
2851 if ( sf->anchor!=NULL ) {
2852 AnchorClass *an;
2853 fprintf(sfd, "AnchorClass2:");
2854 for ( an=sf->anchor; an!=NULL; an=an->next ) {
2855 putc(' ',sfd);
2856 SFDDumpUTF7Str(sfd,an->name);
2857 if ( an->subtable!=NULL ) {
2858 putc(' ',sfd);
2859 SFDDumpUTF7Str(sfd,an->subtable->subtable_name);
2860 }
2861 else
2862 fprintf(sfd, "\"\" ");
2863 }
2864 putc('\n',sfd);
2865 }
2866
2867 if ( sf->subfontcnt!=0 ) {
2868 if ( todir ) {
2869 for ( i=0; i<sf->subfontcnt; ++i ) {
2870 char *subfont = malloc(strlen(dirname)+1+strlen(sf->subfonts[i]->fontname)+20);
2871 char *fontprops;
2872 FILE *ssfd;
2873 sprintf( subfont,"%s/%s" SUBFONT_EXT, dirname, sf->subfonts[i]->fontname );
2874 GFileMkDir(subfont, 0755);
2875 fontprops = malloc(strlen(subfont)+strlen("/" FONT_PROPS)+1);
2876 strcpy(fontprops,subfont); strcat(fontprops,"/" FONT_PROPS);
2877 ssfd = fopen( fontprops,"w");
2878 if ( ssfd!=NULL ) {
2879 err |= SFD_Dump(ssfd,sf->subfonts[i],map,NULL,todir,subfont);
2880 if ( ferror(ssfd) ) err = true;
2881 if ( fclose(ssfd)) err = true;
2882 } else
2883 err = true;
2884 free(fontprops);
2885 free(subfont);
2886 }
2887 } else {
2888 int max;
2889 for ( i=max=0; i<sf->subfontcnt; ++i )
2890 if ( max<sf->subfonts[i]->glyphcnt )
2891 max = sf->subfonts[i]->glyphcnt;
2892 fprintf(sfd, "BeginSubFonts: %d %d\n", sf->subfontcnt, max );
2893 for ( i=0; i<sf->subfontcnt; ++i )
2894 SFD_Dump(sfd,sf->subfonts[i],map,NULL,false, NULL);
2895 fprintf(sfd, "EndSubFonts\n" );
2896 }
2897 } else {
2898 int enccount = map->enccount;
2899 if ( sf->cidmaster!=NULL ) {
2900 realcnt = -1;
2901 enccount = sf->glyphcnt;
2902 } else {
2903 realcnt = 0;
2904 for ( i=0; i<sf->glyphcnt; ++i ) if ( !SFDOmit(sf->glyphs[i]) )
2905 ++realcnt;
2906 if ( realcnt!=sf->glyphcnt ) {
2907 newgids = malloc(sf->glyphcnt*sizeof(int));
2908 realcnt = 0;
2909 for ( i=0; i<sf->glyphcnt; ++i )
2910 if ( SFDOmit(sf->glyphs[i]) )
2911 newgids[i] = -1;
2912 else
2913 newgids[i] = realcnt++;
2914 }
2915 }
2916 if ( !todir )
2917 fprintf(sfd, "BeginChars: %d %d\n",
2918 enccount<map->enc->char_cnt? map->enc->char_cnt : enccount,
2919 realcnt );
2920 for ( i=0; i<sf->glyphcnt; ++i ) {
2921 if ( !SFDOmit(sf->glyphs[i]) ) {
2922 if ( !todir )
2923 SFDDumpChar(sfd,sf->glyphs[i],map,newgids,todir,1);
2924 else {
2925 char *glyphfile = malloc(strlen(dirname)+2*strlen(sf->glyphs[i]->name)+20);
2926 FILE *gsfd;
2927 appendnames(glyphfile,dirname,"/",sf->glyphs[i]->name,GLYPH_EXT );
2928 gsfd = fopen(glyphfile,"w");
2929 if ( gsfd!=NULL ) {
2930 SFDDumpChar(gsfd,sf->glyphs[i],map,newgids,todir,1);
2931 if ( ferror(gsfd)) err = true;
2932 if ( fclose(gsfd)) err = true;
2933 } else
2934 err = true;
2935 free(glyphfile);
2936 }
2937 }
2938 ff_progress_next();
2939 }
2940 if ( !todir )
2941 fprintf(sfd, "EndChars\n" );
2942 }
2943
2944 if ( sf->bitmaps!=NULL )
2945 ff_progress_change_line2(_("Saving Bitmaps"));
2946 for ( bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2947 if ( todir ) {
2948 char *strike = malloc(strlen(dirname)+1+20+20);
2949 char *strikeprops;
2950 FILE *ssfd;
2951 sprintf( strike,"%s/%d" STRIKE_EXT, dirname, bdf->pixelsize );
2952 GFileMkDir(strike, 0755);
2953 strikeprops = malloc(strlen(strike)+strlen("/" STRIKE_PROPS)+1);
2954 strcpy(strikeprops,strike); strcat(strikeprops,"/" STRIKE_PROPS);
2955 ssfd = fopen( strikeprops,"w");
2956 if ( ssfd!=NULL ) {
2957 err |= SFDDumpBitmapFont(ssfd,bdf,map,newgids,todir,strike);
2958 if ( ferror(ssfd) ) err = true;
2959 if ( fclose(ssfd)) err = true;
2960 } else
2961 err = true;
2962 free(strikeprops);
2963 free(strike);
2964 } else
2965 SFDDumpBitmapFont(sfd,bdf,map,newgids,todir,dirname);
2966 }
2967 fprintf(sfd, sf->cidmaster==NULL?"EndSplineFont\n":"EndSubSplineFont\n" );
2968 free(newgids);
2969 return( err );
2970 }
2971
SFD_MIDump(SplineFont * sf,EncMap * map,char * dirname,int mm_pos)2972 static int SFD_MIDump(SplineFont *sf,EncMap *map,char *dirname, int mm_pos) {
2973 char *instance = malloc(strlen(dirname)+1+10+20);
2974 char *fontprops;
2975 FILE *ssfd;
2976 int err = false;
2977
2978 /* I'd like to use the font name, but the order of the instances is */
2979 /* crucial and I must enforce an ordering on them */
2980 sprintf( instance,"%s/mm%d" INSTANCE_EXT, dirname, mm_pos );
2981 GFileMkDir(instance, 0755);
2982 fontprops = malloc(strlen(instance)+strlen("/" FONT_PROPS)+1);
2983 strcpy(fontprops,instance); strcat(fontprops,"/" FONT_PROPS);
2984 ssfd = fopen( fontprops,"w");
2985 if ( ssfd!=NULL ) {
2986 err |= SFD_Dump(ssfd,sf,map,NULL,true,instance);
2987 if ( ferror(ssfd) ) err = true;
2988 if ( fclose(ssfd)) err = true;
2989 } else
2990 err = true;
2991 free(fontprops);
2992 free(instance);
2993 return( err );
2994 }
2995
SFD_MMDump(FILE * sfd,SplineFont * sf,EncMap * map,EncMap * normal,int todir,char * dirname)2996 static int SFD_MMDump(FILE *sfd,SplineFont *sf,EncMap *map,EncMap *normal,
2997 int todir, char *dirname) {
2998 MMSet *mm = sf->mm;
2999 int max, i, j;
3000 int err = false;
3001
3002 fprintf( sfd, "MMCounts: %d %d %d %d\n", mm->instance_count, mm->axis_count,
3003 mm->apple, mm->named_instance_count );
3004 fprintf( sfd, "MMAxis:" );
3005 for ( i=0; i<mm->axis_count; ++i )
3006 fprintf( sfd, " %s", mm->axes[i]);
3007 putc('\n',sfd);
3008 fprintf( sfd, "MMPositions:" );
3009 for ( i=0; i<mm->axis_count*mm->instance_count; ++i )
3010 fprintf( sfd, " %g", (double) mm->positions[i]);
3011 putc('\n',sfd);
3012 fprintf( sfd, "MMWeights:" );
3013 for ( i=0; i<mm->instance_count; ++i )
3014 fprintf( sfd, " %g", (double) mm->defweights[i]);
3015 putc('\n',sfd);
3016 for ( i=0; i<mm->axis_count; ++i ) {
3017 fprintf( sfd, "MMAxisMap: %d %d", i, mm->axismaps[i].points );
3018 for ( j=0; j<mm->axismaps[i].points; ++j )
3019 fprintf( sfd, " %g=>%g", (double) mm->axismaps[i].blends[j], (double) mm->axismaps[i].designs[j]);
3020 fputc('\n',sfd);
3021 SFDDumpMacName(sfd,mm->axismaps[i].axisnames);
3022 }
3023 if ( mm->cdv!=NULL ) {
3024 fprintf( sfd, "MMCDV:\n" );
3025 fputs(mm->cdv,sfd);
3026 fprintf( sfd, "\nEndMMSubroutine\n" );
3027 }
3028 if ( mm->ndv!=NULL ) {
3029 fprintf( sfd, "MMNDV:\n" );
3030 fputs(mm->ndv,sfd);
3031 fprintf( sfd, "\nEndMMSubroutine\n" );
3032 }
3033 for ( i=0; i<mm->named_instance_count; ++i ) {
3034 fprintf( sfd, "MMNamedInstance: %d ", i );
3035 for ( j=0; j<mm->axis_count; ++j )
3036 fprintf( sfd, " %g", (double) mm->named_instances[i].coords[j]);
3037 fputc('\n',sfd);
3038 SFDDumpMacName(sfd,mm->named_instances[i].names);
3039 }
3040
3041 if ( todir ) {
3042 for ( i=0; i<mm->instance_count; ++i )
3043 err |= SFD_MIDump(mm->instances[i],map,dirname,i+1);
3044 err |= SFD_MIDump(mm->normal,map,dirname,0);
3045 } else {
3046 for ( i=max=0; i<mm->instance_count; ++i )
3047 if ( max<mm->instances[i]->glyphcnt )
3048 max = mm->instances[i]->glyphcnt;
3049 fprintf(sfd, "BeginMMFonts: %d %d\n", mm->instance_count+1, max );
3050 for ( i=0; i<mm->instance_count; ++i )
3051 SFD_Dump(sfd,mm->instances[i],map,normal,todir,dirname);
3052 SFD_Dump(sfd,mm->normal,map,normal,todir,dirname);
3053 }
3054 fprintf(sfd, "EndMMFonts\n" );
3055 return( err );
3056 }
3057
SFDDump(FILE * sfd,SplineFont * sf,EncMap * map,EncMap * normal,int todir,char * dirname)3058 static int SFDDump(FILE *sfd,SplineFont *sf,EncMap *map,EncMap *normal,
3059 int todir, char *dirname) {
3060 int i, realcnt;
3061 BDFFont *bdf;
3062 int err = false;
3063
3064 realcnt = sf->glyphcnt;
3065 if ( sf->subfontcnt!=0 ) {
3066 for ( i=0; i<sf->subfontcnt; ++i )
3067 if ( realcnt<sf->subfonts[i]->glyphcnt )
3068 realcnt = sf->subfonts[i]->glyphcnt;
3069 }
3070 for ( i=0, bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next, ++i );
3071 ff_progress_start_indicator(10,_("Saving..."),_("Saving Spline Font Database"),_("Saving Outlines"),
3072 realcnt,i+1);
3073 ff_progress_enable_stop(false);
3074 #ifndef _NO_LIBPNG
3075 double version = 3.2;
3076 if (!WritePNGInSFD) version = 3.1;
3077 #else
3078 double version = 3.1;
3079 #endif
3080 if (!UndoRedoLimitToSave && version == 3.1) {
3081 version = 3.0;
3082 }
3083 fprintf(sfd, "SplineFontDB: %.1f\n", version );
3084 if ( sf->mm != NULL )
3085 err = SFD_MMDump(sfd,sf->mm->normal,map,normal,todir,dirname);
3086 else
3087 err = SFD_Dump(sfd,sf,map,normal,todir,dirname);
3088 ff_progress_end_indicator();
3089 return( err );
3090 }
3091
SFDirClean(char * filename)3092 static void SFDirClean(char *filename) {
3093 DIR *dir;
3094 struct dirent *ent;
3095 char *buffer, *pt;
3096
3097 unlink(filename); /* Just in case it's a normal file, it shouldn't be, but just in case... */
3098 dir = opendir(filename);
3099 if ( dir==NULL )
3100 return;
3101 buffer = malloc(strlen(filename)+1+NAME_MAX+1);
3102 while ( (ent = readdir(dir))!=NULL ) {
3103 if ( strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0 )
3104 continue;
3105 pt = strrchr(ent->d_name,EXT_CHAR);
3106 if ( pt==NULL )
3107 continue;
3108 sprintf( buffer,"%s/%s", filename, ent->d_name );
3109 if ( strcmp(pt,".props")==0 ||
3110 strcmp(pt,GLYPH_EXT)==0 ||
3111 strcmp(pt,BITMAP_EXT)==0 )
3112 unlink( buffer );
3113 else if ( strcmp(pt,STRIKE_EXT)==0 ||
3114 strcmp(pt,SUBFONT_EXT)==0 ||
3115 strcmp(pt,INSTANCE_EXT)==0 )
3116 SFDirClean(buffer);
3117 /* If there are filenames we don't recognize, leave them. They might contain version control info */
3118 }
3119 free(buffer);
3120 closedir(dir);
3121 }
3122
SFFinalDirClean(char * filename)3123 static void SFFinalDirClean(char *filename) {
3124 DIR *dir;
3125 struct dirent *ent;
3126 char *buffer, *markerfile, *pt;
3127
3128 /* we did not unlink sub-directories in case they contained version control */
3129 /* files. We did remove all our files from them, however. If the user */
3130 /* removed a bitmap strike or a cid-subfont those sub-dirs will now be */
3131 /* empty. If the user didn't remove them then they will contain our marker */
3132 /* files. So if we find a subdir with no marker files in it, remove it */
3133 dir = opendir(filename);
3134 if ( dir==NULL )
3135 return;
3136 buffer = malloc(strlen(filename)+1+NAME_MAX+1);
3137 markerfile = malloc(strlen(filename)+2+2*NAME_MAX+1);
3138 while ( (ent = readdir(dir))!=NULL ) {
3139 if ( strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0 )
3140 continue;
3141 pt = strrchr(ent->d_name,EXT_CHAR);
3142 if ( pt==NULL )
3143 continue;
3144 sprintf( buffer,"%s/%s", filename, ent->d_name );
3145 if ( strcmp(pt,".strike")==0 ||
3146 strcmp(pt,SUBFONT_EXT)==0 ||
3147 strcmp(pt,INSTANCE_EXT)==0 ) {
3148 if ( strcmp(pt,".strike")==0 )
3149 sprintf( markerfile,"%s/" STRIKE_PROPS, buffer );
3150 else
3151 sprintf( markerfile,"%s/" FONT_PROPS, buffer );
3152 if ( !GFileExists(markerfile)) {
3153 GFileRemove(buffer, false);
3154 }
3155 }
3156 }
3157 free(buffer);
3158 free(markerfile);
3159 closedir(dir);
3160 }
3161
SFDWrite(char * filename,SplineFont * sf,EncMap * map,EncMap * normal,int todir)3162 int SFDWrite(char *filename,SplineFont *sf,EncMap *map,EncMap *normal,int todir) {
3163 FILE *sfd;
3164 int i, gc;
3165 char *tempfilename = filename;
3166 int err = false;
3167
3168 if ( todir ) {
3169 SFDirClean(filename);
3170 GFileMkDir(filename, 0755); /* this will fail if directory already exists. That's ok */
3171 tempfilename = malloc(strlen(filename)+strlen("/" FONT_PROPS)+1);
3172 strcpy(tempfilename,filename); strcat(tempfilename,"/" FONT_PROPS);
3173 }
3174
3175 sfd = fopen(tempfilename,"w");
3176 if ( tempfilename!=filename ) free(tempfilename);
3177 if ( sfd==NULL )
3178 return( 0 );
3179
3180 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
3181 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
3182 if ( sf->cidmaster!=NULL ) {
3183 sf=sf->cidmaster;
3184 gc = 1;
3185 for ( i=0; i<sf->subfontcnt; ++i )
3186 if ( sf->subfonts[i]->glyphcnt > gc )
3187 gc = sf->subfonts[i]->glyphcnt;
3188 map = EncMap1to1(gc);
3189 err = SFDDump(sfd,sf,map,NULL,todir,filename);
3190 EncMapFree(map);
3191 } else
3192 err = SFDDump(sfd,sf,map,normal,todir,filename);
3193 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
3194 if ( ferror(sfd) ) err = true;
3195 if ( fclose(sfd) ) err = true;
3196 if ( todir )
3197 SFFinalDirClean(filename);
3198 return( !err );
3199 }
3200
SFDDoesAnyBackupExist(char * filename)3201 int SFDDoesAnyBackupExist(char* filename)
3202 {
3203 char path[PATH_MAX];
3204 int idx = 1;
3205
3206 snprintf( path, PATH_MAX, "%s-%02d", filename, idx );
3207 return GFileExists(path);
3208 }
3209
3210 /**
3211 * Handle creation of potential implicit revisions when saving.
3212 *
3213 * If s2d is set then we are saving to an sfdir and no revisions are
3214 * created.
3215 *
3216 * If localRevisionsToRetain == 0 then no revisions are made.
3217 *
3218 * If localRevisionsToRetain > 0 then it is taken as an explict number
3219 * of revisions to make, and revisions are made
3220 *
3221 * If localRevisionsToRetain == -1 then it is "not set".
3222 * In that case, revisions are only made if there are already revisions
3223 * for the locfilename.
3224 *
3225 */
SFDWriteBakExtended(char * locfilename,SplineFont * sf,EncMap * map,EncMap * normal,int s2d,int localRevisionsToRetain)3226 int SFDWriteBakExtended(char* locfilename,
3227 SplineFont *sf,EncMap *map,EncMap *normal,
3228 int s2d,
3229 int localRevisionsToRetain )
3230 {
3231 int rc = 0;
3232
3233 if( s2d )
3234 {
3235 rc = SFDWrite(locfilename,sf,map,normal,s2d);
3236 return rc;
3237 }
3238
3239
3240 int cacheRevisionsToRetain = prefRevisionsToRetain;
3241
3242 sf->save_to_dir = s2d;
3243
3244 if( localRevisionsToRetain < 0 )
3245 {
3246 // If there are no backups, then don't start creating any
3247 if( !SFDDoesAnyBackupExist(sf->filename))
3248 prefRevisionsToRetain = 0;
3249 }
3250 else
3251 {
3252 prefRevisionsToRetain = localRevisionsToRetain;
3253 }
3254
3255 rc = SFDWriteBak( locfilename, sf, map, normal );
3256
3257 prefRevisionsToRetain = cacheRevisionsToRetain;
3258
3259 return rc;
3260 }
3261
3262
SFDWriteBak(char * filename,SplineFont * sf,EncMap * map,EncMap * normal)3263 int SFDWriteBak(char *filename,SplineFont *sf,EncMap *map,EncMap *normal) {
3264 char *buf=0, *buf2=NULL;
3265 int ret;
3266
3267 if ( sf->save_to_dir )
3268 {
3269 ret = SFDWrite(filename,sf,map,normal,true);
3270 return(ret);
3271 }
3272
3273 if ( sf->cidmaster!=NULL )
3274 sf=sf->cidmaster;
3275 buf = malloc(strlen(filename)+10);
3276 if ( sf->compression!=0 )
3277 {
3278 buf2 = malloc(strlen(filename)+10);
3279 strcpy(buf2,filename);
3280 strcat(buf2,compressors[sf->compression-1].ext);
3281 strcpy(buf,buf2);
3282 strcat(buf,"~");
3283 if ( rename(buf2,buf)==0 )
3284 sf->backedup = bs_backedup;
3285 }
3286 else
3287 {
3288 sf->backedup = bs_dontknow;
3289
3290 if( prefRevisionsToRetain )
3291 {
3292 char path[PATH_MAX];
3293 char pathnew[PATH_MAX];
3294 int idx = 0;
3295
3296 snprintf( path, PATH_MAX, "%s", filename );
3297 snprintf( pathnew, PATH_MAX, "%s-%02d", filename, idx );
3298 (void)rename( path, pathnew );
3299
3300 for( idx=prefRevisionsToRetain; idx > 0; idx-- )
3301 {
3302 snprintf( path, PATH_MAX, "%s-%02d", filename, idx-1 );
3303 snprintf( pathnew, PATH_MAX, "%s-%02d", filename, idx );
3304
3305 int rc = rename( path, pathnew );
3306 if( !idx && !rc )
3307 sf->backedup = bs_backedup;
3308 }
3309 idx = prefRevisionsToRetain+1;
3310 snprintf( path, PATH_MAX, "%s-%02d", filename, idx );
3311 unlink(path);
3312 }
3313
3314 }
3315 free(buf);
3316
3317 ret = SFDWrite(filename,sf,map,normal,false);
3318 if ( ret && sf->compression!=0 ) {
3319 unlink(buf2);
3320 buf = malloc(strlen(filename)+40);
3321 sprintf( buf, "%s %s", compressors[sf->compression-1].recomp, filename );
3322 if ( system( buf )!=0 )
3323 sf->compression = 0;
3324 free(buf);
3325 }
3326 free(buf2);
3327 return( ret );
3328 }
3329
3330 /* ********************************* INPUT ********************************** */
3331
getquotedeol(FILE * sfd)3332 char *getquotedeol(FILE *sfd) {
3333 char *pt, *str, *end;
3334 int ch;
3335
3336 pt = str = malloc(101); end = str+100;
3337 while ( isspace(ch = nlgetc(sfd)) && ch!='\r' && ch!='\n' );
3338 while ( ch!='\n' && ch!='\r' && ch!=EOF ) {
3339 if ( ch=='\\' ) {
3340 /* We can't use nlgetc() here, because it would misinterpret */
3341 /* double backslash at the end of line. Multiline strings, */
3342 /* broken with backslash + newline, are just handled above. */
3343 ch = getc(sfd);
3344 if ( ch=='n' ) ch='\n';
3345 /* else if ( ch=='\\' ) ch=='\\'; */ /* second backslash of '\\' */
3346
3347 /* FontForge doesn't write other escape sequences in this context. */
3348 /* So any other value of ch is assumed impossible. */
3349 }
3350 if ( pt>=end ) {
3351 pt = realloc(str,end-str+101);
3352 end = pt+(end-str)+100;
3353 str = pt;
3354 pt = end-100;
3355 }
3356 *pt++ = ch;
3357 ch = nlgetc(sfd);
3358 }
3359 *pt='\0';
3360 /* these strings should be in utf8 now, but some old sfd files might have */
3361 /* latin1. Not a severe problems because they SHOULD be in ASCII. So any */
3362 /* non-ascii strings are erroneous anyway */
3363 if ( !utf8_valid(str) ) {
3364 pt = latin1_2_utf8_copy(str);
3365 free(str);
3366 str = pt;
3367 }
3368 return( str );
3369 }
3370
geteol(FILE * sfd,char * tokbuf)3371 static int geteol(FILE *sfd, char *tokbuf) {
3372 char *pt=tokbuf, *end = tokbuf+2000-2; int ch;
3373
3374 while ( isspace(ch = nlgetc(sfd)) && ch!='\r' && ch!='\n' );
3375 while ( ch!='\n' && ch!='\r' && ch!=EOF ) {
3376 if ( pt<end ) *pt++ = ch;
3377 ch = nlgetc(sfd);
3378 }
3379 *pt='\0';
3380 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
3381 }
visitSFDFragment(FILE * sfd,SplineFont * sf,visitSFDFragmentFunc ufunc,void * udata)3382 void visitSFDFragment( FILE *sfd, SplineFont *sf,
3383 visitSFDFragmentFunc ufunc, void* udata )
3384 {
3385 int eof;
3386 char tok[2000];
3387 while ( 1 ) {
3388 if ( (eof = getname(sfd,tok))!=1 ) {
3389 if ( eof==-1 )
3390 break;
3391 geteol(sfd,tok);
3392 continue;
3393 }
3394
3395 ufunc( sfd, tok, sf, udata );
3396 }
3397 }
3398
3399
getprotectedname(FILE * sfd,char * tokbuf)3400 static int getprotectedname(FILE *sfd, char *tokbuf) {
3401 char *pt=tokbuf, *end = tokbuf+100-2; int ch;
3402
3403 while ( (ch = nlgetc(sfd))==' ' || ch=='\t' );
3404 while ( ch!=EOF && !isspace(ch) && ch!='[' && ch!=']' && ch!='{' && ch!='}' && ch!='<' && ch!='%' ) {
3405 if ( pt<end ) *pt++ = ch;
3406 ch = nlgetc(sfd);
3407 }
3408 if ( pt==tokbuf && ch!=EOF )
3409 *pt++ = ch;
3410 else
3411 ungetc(ch,sfd);
3412 *pt='\0';
3413 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
3414 }
3415
getname(FILE * sfd,char * tokbuf)3416 int getname(FILE *sfd, char *tokbuf) {
3417 int ch;
3418
3419 while ( isspace(ch = nlgetc(sfd)));
3420 ungetc(ch,sfd);
3421 return( getprotectedname(sfd,tokbuf));
3422 }
3423
gettag(FILE * sfd)3424 static uint32 gettag(FILE *sfd) {
3425 int ch, quoted;
3426 uint32 tag;
3427
3428 while ( (ch=nlgetc(sfd))==' ' );
3429 if ( (quoted = (ch=='\'')) ) ch = nlgetc(sfd);
3430 tag = (ch<<24)|(nlgetc(sfd)<<16);
3431 tag |= nlgetc(sfd)<<8;
3432 tag |= nlgetc(sfd);
3433 if ( quoted ) (void) nlgetc(sfd);
3434 return( tag );
3435 }
3436
getint(FILE * sfd,int * val)3437 static int getint(FILE *sfd, int *val) {
3438 char tokbuf[100]; int ch;
3439 char *pt=tokbuf, *end = tokbuf+100-2;
3440
3441 while ( isspace(ch = nlgetc(sfd)));
3442 if ( ch=='-' || ch=='+' ) {
3443 *pt++ = ch;
3444 ch = nlgetc(sfd);
3445 }
3446 while ( isdigit(ch)) {
3447 if ( pt<end ) *pt++ = ch;
3448 ch = nlgetc(sfd);
3449 }
3450 *pt='\0';
3451 ungetc(ch,sfd);
3452 *val = strtol(tokbuf,NULL,10);
3453 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
3454 }
3455
getlonglong(FILE * sfd,long long * val)3456 static int getlonglong(FILE *sfd, long long *val) {
3457 char tokbuf[100]; int ch;
3458 char *pt=tokbuf, *end = tokbuf+100-2;
3459
3460 while ( isspace(ch = nlgetc(sfd)));
3461 if ( ch=='-' || ch=='+' ) {
3462 *pt++ = ch;
3463 ch = nlgetc(sfd);
3464 }
3465 while ( isdigit(ch)) {
3466 if ( pt<end ) *pt++ = ch;
3467 ch = nlgetc(sfd);
3468 }
3469 *pt='\0';
3470 ungetc(ch,sfd);
3471 *val = strtoll(tokbuf,NULL,10);
3472 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
3473 }
3474
gethex(FILE * sfd,uint32 * val)3475 static int gethex(FILE *sfd, uint32 *val) {
3476 char tokbuf[100]; int ch;
3477 char *pt=tokbuf, *end = tokbuf+100-2;
3478
3479 while ( isspace(ch = nlgetc(sfd)));
3480 if ( ch=='#' )
3481 ch = nlgetc(sfd);
3482 if ( ch=='-' || ch=='+' ) {
3483 *pt++ = ch;
3484 ch = nlgetc(sfd);
3485 }
3486 if ( ch=='0' ) {
3487 ch = nlgetc(sfd);
3488 if ( ch=='x' || ch=='X' )
3489 ch = nlgetc(sfd);
3490 else {
3491 ungetc(ch,sfd);
3492 ch = '0';
3493 }
3494 }
3495 while ( isdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F')) {
3496 if ( pt<end ) *pt++ = ch;
3497 ch = nlgetc(sfd);
3498 }
3499 *pt='\0';
3500 ungetc(ch,sfd);
3501 *val = strtoul(tokbuf,NULL,16);
3502 return( pt!=tokbuf?1:ch==EOF?-1: 0 );
3503 }
3504
gethexints(FILE * sfd,uint32 * val,int cnt)3505 static int gethexints(FILE *sfd, uint32 *val, int cnt) {
3506 int i, ch;
3507
3508 for ( i=0; i<cnt; ++i ) {
3509 if ( i!=0 ) {
3510 ch = nlgetc(sfd);
3511 if ( ch!='.' ) ungetc(ch,sfd);
3512 }
3513 if ( !gethex(sfd,&val[i]))
3514 return( false );
3515 }
3516 return( true );
3517 }
3518
getsint(FILE * sfd,int16 * val)3519 static int getsint(FILE *sfd, int16 *val) {
3520 int val2;
3521 int ret = getint(sfd,&val2);
3522 *val = val2;
3523 return( ret );
3524 }
3525
getusint(FILE * sfd,uint16 * val)3526 static int getusint(FILE *sfd, uint16 *val) {
3527 int val2;
3528 int ret = getint(sfd,&val2);
3529 *val = val2;
3530 return( ret );
3531 }
3532
getreal(FILE * sfd,real * val)3533 static int getreal(FILE *sfd, real *val) {
3534 char tokbuf[100];
3535 int ch;
3536 char *pt=tokbuf, *end = tokbuf+100-2, *nend;
3537
3538 while ( isspace(ch = nlgetc(sfd)));
3539 if ( ch!='e' && ch!='E' ) /* real's can't begin with exponants */
3540 while ( isdigit(ch) || ch=='-' || ch=='+' || ch=='e' || ch=='E' || ch=='.' || ch==',' ) {
3541 if ( pt<end ) *pt++ = ch;
3542 ch = nlgetc(sfd);
3543 }
3544 *pt='\0';
3545 ungetc(ch,sfd);
3546 *val = strtod(tokbuf,&nend);
3547 /* Beware of different locals! */
3548 if ( *nend!='\0' ) {
3549 if ( *nend=='.' )
3550 *nend = ',';
3551 else if ( *nend==',' )
3552 *nend = '.';
3553 *val = strtod(tokbuf,&nend);
3554 }
3555 return( pt!=tokbuf && *nend=='\0'?1:ch==EOF?-1: 0 );
3556 }
3557
3558 /* Don't use nlgetc here. We carefully control newlines when dumping in 85 */
3559 /* but backslashes can occur at end of line. */
Dec85(struct enc85 * dec)3560 static int Dec85(struct enc85 *dec) {
3561 int ch1, ch2, ch3, ch4, ch5;
3562 unsigned int val;
3563
3564 if ( dec->pos<0 ) {
3565 while ( isspace(ch1=getc(dec->sfd)));
3566 if ( ch1=='z' ) {
3567 dec->sofar[0] = dec->sofar[1] = dec->sofar[2] = dec->sofar[3] = 0;
3568 dec->pos = 3;
3569 } else {
3570 while ( isspace(ch2=getc(dec->sfd)));
3571 while ( isspace(ch3=getc(dec->sfd)));
3572 while ( isspace(ch4=getc(dec->sfd)));
3573 while ( isspace(ch5=getc(dec->sfd)));
3574 val = ((((ch1-'!')*85+ ch2-'!')*85 + ch3-'!')*85 + ch4-'!')*85 + ch5-'!';
3575 dec->sofar[3] = val>>24;
3576 dec->sofar[2] = val>>16;
3577 dec->sofar[1] = val>>8;
3578 dec->sofar[0] = val;
3579 dec->pos = 3;
3580 }
3581 }
3582 return( dec->sofar[dec->pos--] );
3583 }
3584
rle2image(struct enc85 * dec,int rlelen,struct _GImage * base)3585 static void rle2image(struct enc85 *dec,int rlelen,struct _GImage *base) {
3586 uint8 *pt, *end;
3587 int r,c,set, cnt, ch, ch2;
3588 int i;
3589
3590 r = c = 0; set = 1; pt = base->data; end = pt + base->bytes_per_line*base->height;
3591 memset(base->data,0xff,end-pt);
3592 while ( rlelen>0 ) {
3593 if ( pt>=end ) {
3594 IError( "RLE failure\n" );
3595 while ( rlelen>0 ) { Dec85(dec); --rlelen; }
3596 break;
3597 }
3598 ch = Dec85(dec);
3599 --rlelen;
3600 if ( ch==255 ) {
3601 ch2 = Dec85(dec);
3602 cnt = (ch2<<8) + Dec85(dec);
3603 rlelen -= 2;
3604 } else
3605 cnt = ch;
3606 if ( ch==255 && ch2==0 && cnt<255 ) {
3607 /* Line duplication */
3608 for ( i=0; i<cnt && pt<end; ++i ) {
3609 memcpy(pt,base->data+(r-1)*base->bytes_per_line,base->bytes_per_line);
3610 ++r;
3611 pt += base->bytes_per_line;
3612 }
3613 set = 1;
3614 } else {
3615 if ( pt + ((c+cnt)>>3) > end ) {
3616 IError( "Run length encoded image has been corrupted.\n" );
3617 break;
3618 }
3619 if ( !set ) {
3620 for ( i=0; i<cnt; ++i )
3621 pt[(c+i)>>3] &= ((~0x80)>>((c+i)&7));
3622 }
3623 c += cnt;
3624 set = 1-set;
3625 if ( c>=base->width ) {
3626 ++r;
3627 pt += base->bytes_per_line;
3628 c = 0; set = 1;
3629 }
3630 }
3631 }
3632 }
3633
3634 #ifndef _NO_LIBPNG
3635
3636 enum MIME { UNKNOWN, PNG }; // We only understand PNG for now.
3637
SFDGetImage2MIME(FILE * sfd)3638 enum MIME SFDGetImage2MIME(FILE *sfd) {
3639 char mime[128];
3640
3641 if ( !getname(sfd, mime) ) {
3642 IError("Failed to get a MIME type, file corrupt");
3643 return UNKNOWN;
3644 }
3645
3646 if ( !(strmatch(mime, "image/png")==0) ) {
3647 IError("MIME type received—%s—is not recognized", mime);
3648 return UNKNOWN;
3649 }
3650
3651 return PNG;
3652 }
3653
SFDGetImagePNG(FILE * sfd)3654 static ImageList *SFDGetImagePNG(FILE *sfd) {
3655 int pnglen;
3656 ImageList *img;
3657 struct enc85 dec = {0};
3658 int i, ch;
3659
3660 img = calloc(1,sizeof(ImageList));
3661 dec.pos = -1;
3662 dec.sfd = sfd;
3663
3664 getint(sfd,&pnglen);
3665 getreal(sfd,&img->xoff);
3666 getreal(sfd,&img->yoff);
3667 getreal(sfd,&img->xscale);
3668 getreal(sfd,&img->yscale);
3669
3670 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' )
3671 /* skip */;
3672
3673 char* pngbuf = malloc(pnglen * sizeof(char));
3674 if (pngbuf == NULL) {
3675 IError("Failed to allocate buffer to read PNG in SFD file");
3676 return NULL;
3677 }
3678
3679 for (i = 0; i<pnglen; ++i) {
3680 pngbuf[i] = Dec85(&dec);
3681 }
3682
3683 img->image = GImageReadPngBuf(pngbuf, pnglen);
3684 free(pngbuf);
3685
3686 if (img->image == NULL) {
3687 IError("Failed to read PNG in SFD file, skipping it.");
3688 free(img);
3689 return NULL;
3690 }
3691
3692 img->bb.minx = img->xoff; img->bb.maxy = img->yoff;
3693 img->bb.maxx = img->xoff + GImageGetWidth(img->image)*img->xscale;
3694 img->bb.miny = img->yoff - GImageGetHeight(img->image)*img->yscale;
3695 return img;
3696 }
3697 #endif
3698
SFDGetImage(FILE * sfd)3699 static ImageList *SFDGetImage(FILE *sfd) {
3700 /* We've read the image token */
3701 int width, height, image_type, bpl, clutlen, rlelen;
3702 uint32 trans;
3703 struct _GImage *base;
3704 GImage *image;
3705 ImageList *img;
3706 struct enc85 dec;
3707 int i, ch;
3708
3709 memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
3710 dec.sfd = sfd;
3711
3712 getint(sfd,&width);
3713 getint(sfd,&height);
3714 getint(sfd,&image_type);
3715 getint(sfd,&bpl);
3716 getint(sfd,&clutlen);
3717 gethex(sfd,&trans);
3718 image = GImageCreate(image_type,width,height);
3719 base = image->list_len==0?image->u.image:image->u.images[0];
3720 img = calloc(1,sizeof(ImageList));
3721 img->image = image;
3722 getreal(sfd,&img->xoff);
3723 getreal(sfd,&img->yoff);
3724 getreal(sfd,&img->xscale);
3725 getreal(sfd,&img->yscale);
3726 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
3727 ungetc(ch,sfd);
3728 rlelen = 0;
3729 if ( isdigit(ch))
3730 getint(sfd,&rlelen);
3731 base->trans = trans;
3732 if ( clutlen!=0 ) {
3733 if ( base->clut==NULL )
3734 base->clut = calloc(1,sizeof(GClut));
3735 base->clut->clut_len = clutlen;
3736 base->clut->trans_index = trans;
3737 for ( i=0;i<clutlen; ++i ) {
3738 int r,g,b;
3739 r = Dec85(&dec);
3740 g = Dec85(&dec);
3741 b = Dec85(&dec);
3742 base->clut->clut[i] = (r<<16)|(g<<8)|b;
3743 }
3744 }
3745 if ( rlelen!=0 ) {
3746 rle2image(&dec,rlelen,base);
3747 } else {
3748 for ( i=0; i<height; ++i ) {
3749 if ( image_type==it_rgba ) {
3750 uint32 *ipt = (uint32 *) (base->data + i*base->bytes_per_line);
3751 uint32 *iend = (uint32 *) (base->data + (i+1)*base->bytes_per_line);
3752 int r,g,b, a;
3753 while ( ipt<iend ) {
3754 a = Dec85(&dec);
3755 r = Dec85(&dec);
3756 g = Dec85(&dec);
3757 b = Dec85(&dec);
3758 *ipt++ = (a<<24)|(r<<16)|(g<<8)|b;
3759 }
3760 } else if ( image_type==it_true ) {
3761 int *ipt = (int *) (base->data + i*base->bytes_per_line);
3762 int *iend = (int *) (base->data + (i+1)*base->bytes_per_line);
3763 int r,g,b;
3764 while ( ipt<iend ) {
3765 r = Dec85(&dec);
3766 g = Dec85(&dec);
3767 b = Dec85(&dec);
3768 *ipt++ = (r<<16)|(g<<8)|b;
3769 }
3770 } else {
3771 uint8 *pt = (uint8 *) (base->data + i*base->bytes_per_line);
3772 uint8 *end = (uint8 *) (base->data + (i+1)*base->bytes_per_line);
3773 while ( pt<end ) {
3774 *pt++ = Dec85(&dec);
3775 }
3776 }
3777 }
3778 }
3779 img->bb.minx = img->xoff; img->bb.maxy = img->yoff;
3780 img->bb.maxx = img->xoff + GImageGetWidth(img->image)*img->xscale;
3781 img->bb.miny = img->yoff - GImageGetHeight(img->image)*img->yscale;
3782 /* In old sfd files I failed to recognize bitmap pngs as bitmap, so put */
3783 /* in a little check here that converts things which should be bitmap to */
3784 /* bitmap */ /* Eventually it can be removed as all old sfd files get */
3785 /* converted. 22/10/2002 */
3786 if ( base->image_type==it_index && base->clut!=NULL && base->clut->clut_len==2 )
3787 img->image = ImageAlterClut(img->image);
3788 return( img );
3789 }
3790
SFDGetType1(FILE * sfd)3791 static void SFDGetType1(FILE *sfd) {
3792 /* We've read the OrigType1 token (this is now obselete, but parse it in case there are any old sfds) */
3793 int len;
3794 struct enc85 dec;
3795
3796 memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
3797 dec.sfd = sfd;
3798
3799 getint(sfd,&len);
3800 while ( --len >= 0 )
3801 Dec85(&dec);
3802 }
3803
SFDGetTtfInstrs(FILE * sfd,SplineChar * sc)3804 static void SFDGetTtfInstrs(FILE *sfd, SplineChar *sc) {
3805 /* We've read the TtfInstr token, it is followed by a byte count */
3806 /* and then the instructions in enc85 format */
3807 int i,len;
3808 struct enc85 dec;
3809
3810 memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
3811 dec.sfd = sfd;
3812
3813 getint(sfd,&len);
3814 sc->ttf_instrs = malloc(len);
3815 sc->ttf_instrs_len = len;
3816 for ( i=0; i<len; ++i )
3817 sc->ttf_instrs[i] = Dec85(&dec);
3818 }
3819
tterr(void * UNUSED (rubbish),char * message,int UNUSED (pos))3820 static void tterr(void *UNUSED(rubbish), char *message, int UNUSED(pos)) {
3821 LogError(_("When loading tt instrs from sfd: %s\n"), message );
3822 }
3823
SFDGetTtInstrs(FILE * sfd,SplineChar * sc)3824 static void SFDGetTtInstrs(FILE *sfd, SplineChar *sc) {
3825 /* We've read the TtInstr token, it is followed by text versions of */
3826 /* the instructions, slurp it all into a big buffer, and then parse that */
3827 char *buf=NULL, *pt=buf, *end=buf;
3828 int ch;
3829 int backlen = strlen(end_tt_instrs);
3830 int instr_len;
3831
3832 while ( (ch=nlgetc(sfd))!=EOF ) {
3833 if ( pt>=end ) {
3834 char *newbuf = realloc(buf,(end-buf+200));
3835 pt = newbuf+(pt-buf);
3836 end = newbuf+(end+200-buf);
3837 buf = newbuf;
3838 }
3839 *pt++ = ch;
3840 if ( pt-buf>backlen && strncmp(pt-backlen,end_tt_instrs,backlen)==0 ) {
3841 pt -= backlen;
3842 break;
3843 }
3844 }
3845 *pt = '\0';
3846
3847 sc->ttf_instrs = _IVParse(sc->parent,buf,&instr_len,tterr,NULL);
3848 sc->ttf_instrs_len = instr_len;
3849
3850 free(buf);
3851 }
3852
SFDGetTtfTable(FILE * sfd,SplineFont * sf,struct ttf_table * lasttab[2])3853 static struct ttf_table *SFDGetTtfTable(FILE *sfd, SplineFont *sf,struct ttf_table *lasttab[2]) {
3854 /* We've read the TtfTable token, it is followed by a tag and a byte count */
3855 /* and then the instructions in enc85 format */
3856 int i,len;
3857 int which;
3858 struct enc85 dec;
3859 struct ttf_table *tab = chunkalloc(sizeof(struct ttf_table));
3860
3861 memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
3862 dec.sfd = sfd;
3863
3864 tab->tag = gettag(sfd);
3865
3866 if ( tab->tag==CHR('f','p','g','m') || tab->tag==CHR('p','r','e','p') ||
3867 tab->tag==CHR('c','v','t',' ') || tab->tag==CHR('m','a','x','p'))
3868 which = 0;
3869 else
3870 which = 1;
3871
3872 getint(sfd,&len);
3873 tab->data = malloc(len);
3874 tab->len = len;
3875 for ( i=0; i<len; ++i )
3876 tab->data[i] = Dec85(&dec);
3877
3878 if ( lasttab[which]!=NULL )
3879 lasttab[which]->next = tab;
3880 else if ( which==0 )
3881 sf->ttf_tables = tab;
3882 else
3883 sf->ttf_tab_saved = tab;
3884 lasttab[which] = tab;
3885 return( tab );
3886 }
3887
SFDGetShortTable(FILE * sfd,SplineFont * sf,struct ttf_table * lasttab[2])3888 static struct ttf_table *SFDGetShortTable(FILE *sfd, SplineFont *sf,struct ttf_table *lasttab[2]) {
3889 /* We've read the ShortTable token, it is followed by a tag and a word count */
3890 /* and then the (text) values of the words that make up the cvt table */
3891 int i,len, ch;
3892 uint8 *pt;
3893 int which, iscvt, started;
3894 struct ttf_table *tab = chunkalloc(sizeof(struct ttf_table));
3895
3896 tab->tag = gettag(sfd);
3897
3898 if ( tab->tag==CHR('f','p','g','m') || tab->tag==CHR('p','r','e','p') ||
3899 tab->tag==CHR('c','v','t',' ') || tab->tag==CHR('m','a','x','p'))
3900 which = 0;
3901 else
3902 which = 1;
3903 iscvt = tab->tag==CHR('c','v','t',' ');
3904
3905 getint(sfd,&len);
3906 pt = tab->data = malloc(2*len);
3907 tab->len = 2*len;
3908 started = false;
3909 for ( i=0; i<len; ++i ) {
3910 int num;
3911 getint(sfd,&num);
3912 *pt++ = num>>8;
3913 *pt++ = num&0xff;
3914 if ( iscvt ) {
3915 ch = nlgetc(sfd);
3916 if ( ch==' ' ) {
3917 if ( !started ) {
3918 sf->cvt_names = calloc(len+1,sizeof(char *));
3919 sf->cvt_names[len] = END_CVT_NAMES;
3920 started = true;
3921 }
3922 sf->cvt_names[i] = SFDReadUTF7Str(sfd);
3923 } else
3924 ungetc(ch,sfd);
3925 }
3926 }
3927
3928 if ( lasttab[which]!=NULL )
3929 lasttab[which]->next = tab;
3930 else if ( which==0 )
3931 sf->ttf_tables = tab;
3932 else
3933 sf->ttf_tab_saved = tab;
3934 lasttab[which] = tab;
3935 return( tab );
3936 }
3937
SFDGetTtTable(FILE * sfd,SplineFont * sf,struct ttf_table * lasttab[2])3938 static struct ttf_table *SFDGetTtTable(FILE *sfd, SplineFont *sf,struct ttf_table *lasttab[2]) {
3939 /* We've read the TtTable token, it is followed by a tag */
3940 /* and then the instructions in text format */
3941 int ch;
3942 int which;
3943 struct ttf_table *tab = chunkalloc(sizeof(struct ttf_table));
3944 char *buf=NULL, *pt=buf, *end=buf;
3945 int backlen = strlen(end_tt_instrs);
3946
3947 tab->tag = gettag(sfd);
3948
3949 if ( tab->tag==CHR('f','p','g','m') || tab->tag==CHR('p','r','e','p') ||
3950 tab->tag==CHR('c','v','t',' ') || tab->tag==CHR('m','a','x','p'))
3951 which = 0;
3952 else
3953 which = 1;
3954
3955 while ( (ch=nlgetc(sfd))!=EOF ) {
3956 if ( pt>=end ) {
3957 char *newbuf = realloc(buf,(end-buf+200));
3958 pt = newbuf+(pt-buf);
3959 end = newbuf+(end+200-buf);
3960 buf = newbuf;
3961 }
3962 *pt++ = ch;
3963 if ( pt-buf>backlen && strncmp(pt-backlen,end_tt_instrs,backlen)==0 ) {
3964 pt -= backlen;
3965 break;
3966 }
3967 }
3968 *pt = '\0';
3969 tab->data = _IVParse(sf,buf,&tab->len,tterr,NULL);
3970 free(buf);
3971
3972 if ( lasttab[which]!=NULL )
3973 lasttab[which]->next = tab;
3974 else if ( which==0 )
3975 sf->ttf_tables = tab;
3976 else
3977 sf->ttf_tab_saved = tab;
3978 lasttab[which] = tab;
3979 return( tab );
3980 }
3981
SFDCloseCheck(SplinePointList * spl,int order2)3982 static int SFDCloseCheck(SplinePointList *spl,int order2) {
3983 if ( spl->first!=spl->last &&
3984 RealNear(spl->first->me.x,spl->last->me.x) &&
3985 RealNear(spl->first->me.y,spl->last->me.y)) {
3986 SplinePoint *oldlast = spl->last;
3987 spl->first->prevcp = oldlast->prevcp;
3988 spl->first->noprevcp = oldlast->noprevcp;
3989 oldlast->prev->from->next = NULL;
3990 spl->last = oldlast->prev->from;
3991 chunkfree(oldlast->prev,sizeof(*oldlast));
3992 chunkfree(oldlast->hintmask,sizeof(HintMask));
3993 chunkfree(oldlast,sizeof(*oldlast));
3994 SplineMake(spl->last,spl->first,order2);
3995 spl->last = spl->first;
3996 return( true );
3997 }
3998 return( false );
3999 }
4000
SFDGetHintMask(FILE * sfd,HintMask * hintmask)4001 static void SFDGetHintMask(FILE *sfd,HintMask *hintmask) {
4002 int nibble = 0, ch;
4003
4004 memset(hintmask,0,sizeof(HintMask));
4005 for (;;) {
4006 ch = nlgetc(sfd);
4007 if ( isdigit(ch))
4008 ch -= '0';
4009 else if ( ch>='a' && ch<='f' )
4010 ch -= 'a'-10;
4011 else if ( ch>='A' && ch<='F' )
4012 ch -= 'A'-10;
4013 else {
4014 ungetc(ch,sfd);
4015 break;
4016 }
4017 if ( nibble<2*HntMax/8 )
4018 (*hintmask)[nibble>>1] |= ch<<(4*(1-(nibble&1)));
4019 ++nibble;
4020 }
4021 }
4022
SFDGetSpiros(FILE * sfd,SplineSet * cur)4023 static void SFDGetSpiros(FILE *sfd,SplineSet *cur) {
4024 int ch;
4025 spiro_cp cp;
4026
4027 ch = nlgetc(sfd); /* S */
4028 ch = nlgetc(sfd); /* p */
4029 ch = nlgetc(sfd); /* i */
4030 ch = nlgetc(sfd); /* r */
4031 ch = nlgetc(sfd); /* o */
4032 while ( fscanf(sfd,"%lg %lg %c", &cp.x, &cp.y, &cp.ty )==3 ) {
4033 if ( cur!=NULL ) {
4034 if ( cur->spiro_cnt>=cur->spiro_max )
4035 cur->spiros = realloc(cur->spiros,
4036 (cur->spiro_max+=10)*sizeof(spiro_cp));
4037 cur->spiros[cur->spiro_cnt++] = cp;
4038 }
4039 }
4040 if ( cur!=NULL && cur->spiro_cnt>0
4041 && (cur->spiros[cur->spiro_cnt-1].ty&0x7f)!=SPIRO_END ) {
4042 if ( cur->spiro_cnt>=cur->spiro_max )
4043 cur->spiros = realloc(cur->spiros,
4044 (cur->spiro_max+=1)*sizeof(spiro_cp));
4045 memset(&cur->spiros[cur->spiro_cnt],0,sizeof(spiro_cp));
4046 cur->spiros[cur->spiro_cnt++].ty = SPIRO_END;
4047 }
4048 ch = nlgetc(sfd);
4049 if ( ch=='E' ) {
4050 ch = nlgetc(sfd); /* n */
4051 ch = nlgetc(sfd); /* d */
4052 ch = nlgetc(sfd); /* S */
4053 ch = nlgetc(sfd); /* p */
4054 ch = nlgetc(sfd); /* i */
4055 ch = nlgetc(sfd); /* r */
4056 ch = nlgetc(sfd); /* o */
4057 } else
4058 ungetc(ch,sfd);
4059 }
4060
SFDGetSplineSet(FILE * sfd,int order2)4061 static SplineSet *SFDGetSplineSet(FILE *sfd,int order2) {
4062 SplinePointList *cur=NULL, *head=NULL;
4063 BasePoint current;
4064 real stack[100];
4065 int sp=0;
4066 SplinePoint *pt = NULL;
4067 int ch;
4068 int ch2;
4069 char tok[100];
4070 int ttfindex = 0;
4071 int lastacceptable;
4072 int flags = 0, tmp;
4073
4074 current.x = current.y = 0;
4075 lastacceptable = 0;
4076 while ( 1 ) {
4077
4078 while ( getreal(sfd,&stack[sp])==1 )
4079 if ( sp<99 )
4080 ++sp;
4081 while ( isspace(ch=nlgetc(sfd)));
4082 if ( ch=='E' || ch=='e' || ch==EOF )
4083 break;
4084 if ( ch=='S' ) {
4085 ungetc(ch,sfd);
4086 SFDGetSpiros(sfd,cur);
4087 continue;
4088 } else if (( ch=='N' ) &&
4089 nlgetc(sfd)=='a' && /* a */
4090 nlgetc(sfd)=='m' && /* m */
4091 nlgetc(sfd)=='e' && /* e */
4092 nlgetc(sfd)=='d' ) /* d */ {
4093 ch2 = nlgetc(sfd); /* : */
4094 // We are either fetching a splineset name (Named:) or a point name (NamedP:).
4095 if (ch2=='P') { if ((nlgetc(sfd)==':') && (pt!=NULL)) { if (pt->name!=NULL) {free(pt->name);} pt->name = SFDReadUTF7Str(sfd); } }
4096 else if (ch2==':') { if (cur != NULL) cur->contour_name = SFDReadUTF7Str(sfd); else { char * freetmp = SFDReadUTF7Str(sfd); free(freetmp); freetmp = NULL; } }
4097 continue;
4098 } else if ( ch=='P' && PeekMatch(sfd,"ath") ) {
4099 int flags;
4100 nlgetc(sfd); /* a */
4101 nlgetc(sfd); /* t */
4102 nlgetc(sfd); /* h */
4103 if (PeekMatch(sfd,"Flags:")) {
4104 nlgetc(sfd); /* F */
4105 nlgetc(sfd); /* l */
4106 nlgetc(sfd); /* a */
4107 nlgetc(sfd); /* g */
4108 nlgetc(sfd); /* s */
4109 nlgetc(sfd); /* : */
4110 getint(sfd,&flags);
4111 if (cur != NULL) cur->is_clip_path = flags&1;
4112 } else if (PeekMatch(sfd,"Start:")) {
4113 nlgetc(sfd); /* S */
4114 nlgetc(sfd); /* t */
4115 nlgetc(sfd); /* a */
4116 nlgetc(sfd); /* r */
4117 nlgetc(sfd); /* t */
4118 nlgetc(sfd); /* : */
4119 getint(sfd,&flags);
4120 if (cur != NULL) cur->start_offset = flags;
4121 }
4122 }
4123 pt = NULL;
4124 if ( ch=='l' || ch=='m' ) {
4125 if ( sp>=2 ) {
4126 current.x = stack[sp-2];
4127 current.y = stack[sp-1];
4128 sp -= 2;
4129 pt = chunkalloc(sizeof(SplinePoint));
4130 pt->me = current;
4131 pt->noprevcp = true; pt->nonextcp = true;
4132 if ( ch=='m' ) {
4133 SplinePointList *spl = chunkalloc(sizeof(SplinePointList));
4134 spl->first = spl->last = pt;
4135 spl->start_offset = 0;
4136 if ( cur!=NULL ) {
4137 if ( !(flags & SFD_PTFLAG_FORCE_OPEN_PATH) && SFDCloseCheck(cur,order2) )
4138 --ttfindex;
4139 cur->next = spl;
4140 } else
4141 head = spl;
4142 cur = spl;
4143 } else {
4144 if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
4145 if ( cur->last->nextcpindex==0xfffe )
4146 cur->last->nextcpindex = 0xffff;
4147 SplineMake(cur->last,pt,order2);
4148 cur->last->nonextcp = 1;
4149 pt->noprevcp = 1;
4150 cur->last = pt;
4151 }
4152 }
4153 } else
4154 sp = 0;
4155 } else if ( ch=='c' ) {
4156 if ( sp>=6 ) {
4157 current.x = stack[sp-2];
4158 current.y = stack[sp-1];
4159
4160 if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
4161 cur->last->nextcp.x = stack[sp-6];
4162 cur->last->nextcp.y = stack[sp-5];
4163 cur->last->nonextcp = false;
4164 pt = chunkalloc(sizeof(SplinePoint));
4165 pt->prevcp.x = stack[sp-4];
4166 pt->prevcp.y = stack[sp-3];
4167 pt->me = current;
4168 pt->nonextcp = true;
4169 if ( cur->last->nextcpindex==0xfffe )
4170 cur->last->nextcpindex = ttfindex++;
4171 else if ( cur->last->nextcpindex!=0xffff )
4172 ttfindex = cur->last->nextcpindex+1;
4173 SplineMake(cur->last,pt,order2);
4174 cur->last = pt;
4175 }
4176
4177 sp -= 6;
4178 } else
4179 sp = 0;
4180 }
4181 if ( pt!=NULL ) {
4182 getint(sfd,&flags);
4183
4184 pt->pointtype = (flags & SFD_PTFLAG_TYPE_MASK);
4185 pt->selected = (flags & SFD_PTFLAG_IS_SELECTED) > 0;
4186 pt->nextcpdef = (flags & SFD_PTFLAG_NEXTCP_IS_DEFAULT) > 0;
4187 pt->prevcpdef = (flags & SFD_PTFLAG_PREVCP_IS_DEFAULT) > 0;
4188 pt->roundx = (flags & SFD_PTFLAG_ROUND_IN_X) > 0;
4189 pt->roundy = (flags & SFD_PTFLAG_ROUND_IN_Y) > 0;
4190 pt->dontinterpolate = (flags & SFD_PTFLAG_INTERPOLATE_NEVER) > 0;
4191 if ( pt->prev!=NULL )
4192 pt->prev->acceptableextrema = (flags & SFD_PTFLAG_PREV_EXTREMA_MARKED_ACCEPTABLE) > 0;
4193 else
4194 lastacceptable = (flags & SFD_PTFLAG_PREV_EXTREMA_MARKED_ACCEPTABLE) > 0;
4195 if ( flags&0x80 )
4196 pt->ttfindex = 0xffff;
4197 else
4198 pt->ttfindex = ttfindex++;
4199 pt->nextcpindex = 0xfffe;
4200 ch = nlgetc(sfd);
4201 if ( ch=='x' ) {
4202 pt->hintmask = chunkalloc(sizeof(HintMask));
4203 SFDGetHintMask(sfd,pt->hintmask);
4204 } else if ( ch!=',' )
4205 ungetc(ch,sfd);
4206 else {
4207 ch = nlgetc(sfd);
4208 if ( ch==',' )
4209 pt->ttfindex = 0xfffe;
4210 else {
4211 ungetc(ch,sfd);
4212 getint(sfd,&tmp);
4213 pt->ttfindex = tmp;
4214 nlgetc(sfd); /* skip comma */
4215 if ( tmp!=-1 )
4216 ttfindex = tmp+1;
4217 }
4218 ch = nlgetc(sfd);
4219 if ( ch=='\r' || ch=='\n' )
4220 ungetc(ch,sfd);
4221 else {
4222 ungetc(ch,sfd);
4223 getint(sfd,&tmp);
4224 pt->nextcpindex = tmp;
4225 if ( tmp!=-1 )
4226 ttfindex = tmp+1;
4227 }
4228 }
4229 } else
4230 flags = 0;
4231 }
4232 if ( cur!=NULL && !(flags & SFD_PTFLAG_FORCE_OPEN_PATH) )
4233 SFDCloseCheck(cur,order2);
4234 if ( lastacceptable && cur->last->prev!=NULL )
4235 cur->last->prev->acceptableextrema = true;
4236 getname(sfd,tok);
4237 return( head );
4238 }
4239
SFDGetUndo(FILE * sfd,SplineChar * sc,const char * startTag,int current_layer)4240 Undoes *SFDGetUndo( FILE *sfd, SplineChar *sc,
4241 const char* startTag,
4242 int current_layer )
4243 {
4244 Undoes *u = 0;
4245 char tok[2000];
4246 int i;
4247 RefChar *lastr=NULL;
4248 ImageList *lasti=NULL;
4249 AnchorPoint *lastap = NULL;
4250 GuidelineSet *lastgl = NULL;
4251 SplineChar* tsc = 0;
4252
4253 if ( getname(sfd,tok)!=1 )
4254 return( NULL );
4255 if ( strcmp(tok, startTag) )
4256 return( NULL );
4257
4258 u = chunkalloc(sizeof(Undoes));
4259 u->undotype = ut_state;
4260 u->layer = UNDO_LAYER_UNKNOWN;
4261
4262 while ( 1 )
4263 {
4264 if ( getname(sfd,tok)!=1 ) {
4265 chunkfree(u,sizeof(Undoes));
4266 return( NULL );
4267 }
4268
4269 if ( !strmatch(tok,"EndUndoOperation")
4270 || !strmatch(tok,"EndRedoOperation"))
4271 {
4272 if( u->undotype == ut_hints ) {
4273 if( tsc ) {
4274 u->u.state.hints = UHintCopy(tsc,1);
4275 SplineCharFree( tsc );
4276 }
4277 }
4278
4279 return u;
4280 }
4281 if ( !strmatch(tok,"Index:")) {
4282 getint(sfd,&i);
4283 }
4284 if ( !strmatch(tok,"Type:")) {
4285 getint(sfd,&i);
4286 u->undotype = i;
4287 if( u->undotype == ut_hints ) {
4288 tsc = SplineCharCopy( sc, 0, 0 );
4289 tsc->hstem = 0;
4290 tsc->vstem = 0;
4291 tsc->dstem = 0;
4292 }
4293 }
4294 if ( !strmatch(tok,"WasModified:")) {
4295 getint(sfd,&i);
4296 u->was_modified = i;
4297 }
4298 if ( !strmatch(tok,"WasOrder2:")) {
4299 getint(sfd,&i);
4300 u->was_order2 = i;
4301 }
4302 if ( !strmatch(tok,"Layer:")) {
4303 getint(sfd,&i);
4304 u->layer = i;
4305 }
4306
4307 switch( u->undotype )
4308 {
4309 case ut_tstate:
4310 case ut_state:
4311 if ( !strmatch(tok,"Width:")) { getint(sfd,&i); u->u.state.width = i; }
4312 if ( !strmatch(tok,"VWidth:")) { getint(sfd,&i); u->u.state.vwidth = i; }
4313 if ( !strmatch(tok,"LBearingChange:")) { getint(sfd,&i); u->u.state.lbearingchange = i; }
4314 if ( !strmatch(tok,"UnicodeEnc:")) { getint(sfd,&i); u->u.state.unicodeenc = i; }
4315 if ( !strmatch(tok,"Charname:")) { u->u.state.charname = getquotedeol(sfd); }
4316 if ( !strmatch(tok,"Comment:")) { u->u.state.comment = getquotedeol(sfd); }
4317
4318 if( !strmatch(tok,"Refer:"))
4319 {
4320 RefChar *ref = SFDGetRef(sfd,strmatch(tok,"Ref:")==0);
4321 int i=0;
4322 for( i=0; i< ref->layer_cnt; i++ ) {
4323 ref->layers[i].splines = 0;
4324 }
4325 if ( !u->u.state.refs )
4326 u->u.state.refs = ref;
4327 else
4328 lastr->next = ref;
4329 lastr = ref;
4330 }
4331
4332 if( !strmatch(tok,"Image:"))
4333 {
4334 ImageList *img = SFDGetImage(sfd);
4335 if (img != NULL) {
4336 if ( !u->u.state.images )
4337 u->u.state.images = img;
4338 else
4339 lasti->next = img;
4340 lasti = img;
4341 }
4342 }
4343
4344 if( !strmatch(tok,"Image2:"))
4345 {
4346 #ifndef _NO_LIBPNG
4347 enum MIME mime = SFDGetImage2MIME(sfd);
4348 if (mime == PNG) {
4349 ImageList *img = SFDGetImagePNG(sfd);
4350 if (img != NULL) {
4351 if ( !u->u.state.images )
4352 u->u.state.images = img;
4353 else
4354 lasti->next = img;
4355 lasti = img;
4356 }
4357 } else
4358 #endif
4359 {
4360 LogError(_("Image2 skipped as it uses an unsupported image type"));
4361 const char* im2_terminator[] = { "EndImage2", 0 };
4362 SFDConsumeUntil(sfd, im2_terminator);
4363 }
4364 }
4365
4366 if( !strmatch(tok,"Comment:")) {
4367 u->u.state.comment = getquotedeol(sfd);
4368 }
4369 if( !strmatch(tok,"InstructionsLength:")) {
4370 getint(sfd,&i); u->u.state.instrs_len = i;
4371 }
4372 if( !strmatch(tok,"AnchorPoint:") ) {
4373 lastap = SFDReadAnchorPoints( sfd, sc, &(u->u.state.anchor), lastap );
4374 }
4375 if ( !strmatch(tok,"SplineSet")) {
4376 u->u.state.splines = SFDGetSplineSet(sfd,sc->layers[current_layer].order2);
4377 }
4378 break;
4379 case ut_hints:
4380 {
4381 if ( !strmatch(tok,"HStem:") ) {
4382 tsc->hstem = SFDReadHints(sfd);
4383 tsc->hconflicts = StemListAnyConflicts(tsc->hstem);
4384 }
4385 else if ( !strmatch(tok,"VStem:") ) {
4386 tsc->vstem = SFDReadHints(sfd);
4387 tsc->vconflicts = StemListAnyConflicts(tsc->vstem);
4388 }
4389 else if( !strmatch(tok,"DStem2:"))
4390 tsc->dstem = SFDReadDHints( sc->parent,sfd,false );
4391 else if( !strmatch(tok,"TtInstrs:")) {
4392 SFDGetTtInstrs(sfd,tsc);
4393 u->u.state.instrs = tsc->ttf_instrs;
4394 u->u.state.instrs_len = tsc->ttf_instrs_len;
4395 tsc->ttf_instrs = 0;
4396 tsc->ttf_instrs_len = 0;
4397 }
4398 break;
4399 }
4400
4401 case ut_width:
4402 case ut_vwidth:
4403 if( !strmatch(tok,"Width:")) {
4404 getint(sfd,&i); u->u.width = i;
4405 }
4406 break;
4407 default:
4408 break;
4409 }
4410 }
4411
4412 return u;
4413 }
4414
SFDGetMinimumDistances(FILE * sfd,SplineChar * sc)4415 static void SFDGetMinimumDistances(FILE *sfd, SplineChar *sc) {
4416 SplineSet *ss;
4417 SplinePoint *sp;
4418 int pt,i, val, err;
4419 int ch;
4420 SplinePoint **mapping=NULL;
4421 MinimumDistance *last, *md, *mdhead=NULL;
4422
4423 for ( i=0; i<2; ++i ) {
4424 pt = 0;
4425 for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) {
4426 for ( sp=ss->first; ; ) {
4427 if ( mapping!=NULL ) mapping[pt] = sp;
4428 pt++;
4429 if ( sp->next == NULL )
4430 break;
4431 sp = sp->next->to;
4432 if ( sp==ss->first )
4433 break;
4434 }
4435 }
4436 if ( mapping==NULL )
4437 mapping = calloc(pt,sizeof(SplinePoint *));
4438 }
4439
4440 last = NULL;
4441 for ( ch=nlgetc(sfd); ch!=EOF && ch!='\n'; ch=nlgetc(sfd)) {
4442 err = false;
4443 while ( isspace(ch) && ch!='\n' ) ch=nlgetc(sfd);
4444 if ( ch=='\n' )
4445 break;
4446 md = chunkalloc(sizeof(MinimumDistance));
4447 if ( ch=='x' ) md->x = true;
4448 getint(sfd,&val);
4449 if ( val<-1 || val>=pt ) {
4450 IError( "Minimum Distance specifies bad point (%d) in sfd file\n", val );
4451 err = true;
4452 } else if ( val!=-1 ) {
4453 md->sp1 = mapping[val];
4454 md->sp1->dontinterpolate = true;
4455 }
4456 ch = nlgetc(sfd);
4457 if ( ch!=',' ) {
4458 IError( "Minimum Distance lacks a comma where expected\n" );
4459 err = true;
4460 }
4461 getint(sfd,&val);
4462 if ( val<-1 || val>=pt ) {
4463 IError( "Minimum Distance specifies bad point (%d) in sfd file\n", val );
4464 err = true;
4465 } else if ( val!=-1 ) {
4466 md->sp2 = mapping[val];
4467 md->sp2->dontinterpolate = true;
4468 }
4469 if ( !err ) {
4470 if ( last!=NULL )
4471 last->next = md;
4472 last = md;
4473 } else
4474 chunkfree(md,sizeof(MinimumDistance));
4475 }
4476 free(mapping);
4477
4478 /* Obsolete concept */
4479 MinimumDistancesFree(mdhead);
4480 }
4481
SFDReadHintInstances(FILE * sfd,StemInfo * stem)4482 static HintInstance *SFDReadHintInstances(FILE *sfd, StemInfo *stem) {
4483 HintInstance *head=NULL, *last=NULL, *cur;
4484 real begin, end;
4485 int ch;
4486
4487 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
4488 if ( ch=='G' && stem != NULL ) {
4489 stem->ghost = true;
4490 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
4491 }
4492 if ( ch!='<' ) {
4493 ungetc(ch,sfd);
4494 return(NULL);
4495 }
4496 while ( getreal(sfd,&begin)==1 && getreal(sfd,&end)) {
4497 cur = chunkalloc(sizeof(HintInstance));
4498 cur->begin = begin;
4499 cur->end = end;
4500 if ( head == NULL )
4501 head = cur;
4502 else
4503 last->next = cur;
4504 last = cur;
4505 }
4506 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
4507 if ( ch!='>' )
4508 ungetc(ch,sfd);
4509 return( head );
4510 }
4511
SFDReadHints(FILE * sfd)4512 static StemInfo *SFDReadHints(FILE *sfd) {
4513 StemInfo *head=NULL, *last=NULL, *cur;
4514 real start, width;
4515
4516 while ( getreal(sfd,&start)==1 && getreal(sfd,&width)) {
4517 cur = chunkalloc(sizeof(StemInfo));
4518 cur->start = start;
4519 cur->width = width;
4520 cur->where = SFDReadHintInstances(sfd,cur);
4521 if ( head == NULL )
4522 head = cur;
4523 else
4524 last->next = cur;
4525 last = cur;
4526 }
4527 return( head );
4528 }
4529
SFDReadDHints(SplineFont * sf,FILE * sfd,int old)4530 static DStemInfo *SFDReadDHints( SplineFont *sf,FILE *sfd,int old ) {
4531 DStemInfo *head=NULL, *last=NULL, *cur;
4532 int i;
4533 BasePoint bp[4], *bpref[4], left, right, unit;
4534 double rstartoff, rendoff, lendoff;
4535
4536 if ( old ) {
4537 for ( i=0 ; i<4 ; i++ ) bpref[i] = &bp[i];
4538
4539 while ( getreal( sfd,&bp[0].x ) && getreal( sfd,&bp[0].y ) &&
4540 getreal( sfd,&bp[1].x ) && getreal( sfd,&bp[1].y ) &&
4541 getreal( sfd,&bp[2].x ) && getreal( sfd,&bp[2].y ) &&
4542 getreal( sfd,&bp[3].x ) && getreal( sfd,&bp[3].y )) {
4543
4544 /* Ensure point coordinates specified in the sfd file do */
4545 /* form a diagonal line */
4546 if ( PointsDiagonalable( sf,bpref,&unit )) {
4547 cur = chunkalloc( sizeof( DStemInfo ));
4548 cur->left = *bpref[0];
4549 cur->right = *bpref[1];
4550 cur->unit = unit;
4551 /* Generate a temporary hint instance, so that the hint can */
4552 /* be visible in charview even if subsequent rebuilding instances */
4553 /* fails (e. g. for composite characters) */
4554 cur->where = chunkalloc( sizeof( HintInstance ));
4555 rstartoff = ( cur->right.x - cur->left.x ) * cur->unit.x +
4556 ( cur->right.y - cur->left.y ) * cur->unit.y;
4557 rendoff = ( bpref[2]->x - cur->left.x ) * cur->unit.x +
4558 ( bpref[2]->y - cur->left.y ) * cur->unit.y;
4559 lendoff = ( bpref[3]->x - cur->left.x ) * cur->unit.x +
4560 ( bpref[3]->y - cur->left.y ) * cur->unit.y;
4561 cur->where->begin = ( rstartoff > 0 ) ? rstartoff : 0;
4562 cur->where->end = ( rendoff > lendoff ) ? lendoff : rendoff;
4563 MergeDStemInfo( sf,&head,cur );
4564 }
4565 }
4566 } else {
4567 while ( getreal( sfd,&left.x ) && getreal( sfd,&left.y ) &&
4568 getreal( sfd,&right.x ) && getreal( sfd,&right.y ) &&
4569 getreal( sfd,&unit.x ) && getreal( sfd,&unit.y )) {
4570 cur = chunkalloc( sizeof( DStemInfo ));
4571 cur->left = left;
4572 cur->right = right;
4573 cur->unit = unit;
4574 cur->where = SFDReadHintInstances( sfd,NULL );
4575 if ( head == NULL )
4576 head = cur;
4577 else
4578 last->next = cur;
4579 last = cur;
4580 }
4581 }
4582 return( head );
4583 }
4584
SFDReadDeviceTable(FILE * sfd,DeviceTable * adjust)4585 static DeviceTable *SFDReadDeviceTable(FILE *sfd,DeviceTable *adjust) {
4586 int i, junk, first, last, ch, len;
4587
4588 while ( (ch=nlgetc(sfd))==' ' );
4589 if ( ch=='{' ) {
4590 while ( (ch=nlgetc(sfd))==' ' );
4591 if ( ch=='}' )
4592 return(NULL);
4593 else
4594 ungetc(ch,sfd);
4595 getint(sfd,&first);
4596 ch = nlgetc(sfd); /* Should be '-' */
4597 getint(sfd,&last);
4598 len = last-first+1;
4599 if ( len<=0 ) {
4600 IError( "Bad device table, invalid length.\n" );
4601 return(NULL);
4602 }
4603 if ( adjust==NULL )
4604 adjust = chunkalloc(sizeof(DeviceTable));
4605 adjust->first_pixel_size = first;
4606 adjust->last_pixel_size = last;
4607 adjust->corrections = malloc(len);
4608 for ( i=0; i<len; ++i ) {
4609 while ( (ch=nlgetc(sfd))==' ' );
4610 if ( ch!=',' ) ungetc(ch,sfd);
4611 getint(sfd,&junk);
4612 adjust->corrections[i] = junk;
4613 }
4614 while ( (ch=nlgetc(sfd))==' ' );
4615 if ( ch!='}' ) ungetc(ch,sfd);
4616 } else
4617 ungetc(ch,sfd);
4618 return( adjust );
4619 }
4620
SFDReadValDevTab(FILE * sfd)4621 static ValDevTab *SFDReadValDevTab(FILE *sfd) {
4622 int i, j, ch;
4623 ValDevTab vdt;
4624 char buf[4];
4625
4626 memset(&vdt,0,sizeof(vdt));
4627 buf[3] = '\0';
4628 while ( (ch=nlgetc(sfd))==' ' );
4629 if ( ch=='[' ) {
4630 for ( i=0; i<4; ++i ) {
4631 while ( (ch=nlgetc(sfd))==' ' );
4632 if ( ch==']' )
4633 break;
4634 buf[0]=ch;
4635 for ( j=1; j<3; ++j ) buf[j]=nlgetc(sfd);
4636 while ( (ch=nlgetc(sfd))==' ' );
4637 if ( ch!='=' ) ungetc(ch,sfd);
4638 SFDReadDeviceTable(sfd,
4639 strcmp(buf,"ddx")==0 ? &vdt.xadjust :
4640 strcmp(buf,"ddy")==0 ? &vdt.yadjust :
4641 strcmp(buf,"ddh")==0 ? &vdt.xadv :
4642 strcmp(buf,"ddv")==0 ? &vdt.yadv :
4643 (&vdt.xadjust) + i );
4644 while ( (ch=nlgetc(sfd))==' ' );
4645 if ( ch!=']' ) ungetc(ch,sfd);
4646 else
4647 break;
4648 }
4649 if ( vdt.xadjust.corrections!=NULL || vdt.yadjust.corrections!=NULL ||
4650 vdt.xadv.corrections!=NULL || vdt.yadv.corrections!=NULL ) {
4651 ValDevTab *v = chunkalloc(sizeof(ValDevTab));
4652 *v = vdt;
4653 return( v );
4654 }
4655 } else
4656 ungetc(ch,sfd);
4657 return( NULL );
4658 }
4659
SFDReadAnchorPoints(FILE * sfd,SplineChar * sc,AnchorPoint ** alist,AnchorPoint * lastap)4660 static AnchorPoint *SFDReadAnchorPoints(FILE *sfd,SplineChar *sc,AnchorPoint** alist, AnchorPoint *lastap)
4661 {
4662 AnchorPoint *ap = chunkalloc(sizeof(AnchorPoint));
4663 AnchorClass *an;
4664 char *name;
4665 char tok[200];
4666 int ch;
4667
4668 name = SFDReadUTF7Str(sfd);
4669 if ( name==NULL ) {
4670 LogError(_("Anchor Point with no class name: %s"), sc->name );
4671 AnchorPointsFree(ap);
4672 return( lastap );
4673 }
4674 for ( an=sc->parent->anchor; an!=NULL && strcmp(an->name,name)!=0; an=an->next );
4675 free(name);
4676 ap->anchor = an;
4677 getreal(sfd,&ap->me.x);
4678 getreal(sfd,&ap->me.y);
4679 ap->type = -1;
4680 if ( getname(sfd,tok)==1 ) {
4681 if ( strcmp(tok,"mark")==0 )
4682 ap->type = at_mark;
4683 else if ( strcmp(tok,"basechar")==0 )
4684 ap->type = at_basechar;
4685 else if ( strcmp(tok,"baselig")==0 )
4686 ap->type = at_baselig;
4687 else if ( strcmp(tok,"basemark")==0 )
4688 ap->type = at_basemark;
4689 else if ( strcmp(tok,"entry")==0 )
4690 ap->type = at_centry;
4691 else if ( strcmp(tok,"exit")==0 )
4692 ap->type = at_cexit;
4693 }
4694 getsint(sfd,&ap->lig_index);
4695 ch = nlgetc(sfd);
4696 ungetc(ch,sfd);
4697 if ( ch==' ' ) {
4698 SFDReadDeviceTable(sfd,&ap->xadjust);
4699 SFDReadDeviceTable(sfd,&ap->yadjust);
4700 ch = nlgetc(sfd);
4701 ungetc(ch,sfd);
4702 if ( isdigit(ch)) {
4703 getsint(sfd,(int16 *) &ap->ttf_pt_index);
4704 ap->has_ttf_pt = true;
4705 }
4706 }
4707 if ( ap->anchor==NULL || ap->type==-1 ) {
4708 LogError(_("Bad Anchor Point: %s"), sc->name );
4709 AnchorPointsFree(ap);
4710 return( lastap );
4711 }
4712 if ( lastap==NULL )
4713 (*alist) = ap;
4714 else
4715 lastap->next = ap;
4716
4717 return( ap );
4718 }
4719
SFDReadGuideline(FILE * sfd,GuidelineSet ** gll,GuidelineSet * lastgl)4720 static GuidelineSet *SFDReadGuideline(FILE *sfd, GuidelineSet **gll, GuidelineSet *lastgl)
4721 {
4722 GuidelineSet *gl = chunkalloc(sizeof(GuidelineSet));
4723 gl->name = SFDReadUTF7Str(sfd);
4724 gl->identifier = SFDReadUTF7Str(sfd);
4725 getreal(sfd,&gl->point.x);
4726 getreal(sfd,&gl->point.y);
4727 getreal(sfd,&gl->angle);
4728 getint(sfd,&gl->color);
4729 getint(sfd,&gl->flags);
4730 if ( lastgl!=NULL )
4731 lastgl->next = gl;
4732 else if (gll)
4733 *gll = gl;
4734 return( gl );
4735 }
4736
SFDGetRef(FILE * sfd,int was_enc)4737 static RefChar *SFDGetRef(FILE *sfd, int was_enc) {
4738 RefChar *rf;
4739 int temp=0, ch;
4740
4741 rf = RefCharCreate();
4742 getint(sfd,&rf->orig_pos);
4743 rf->encoded = was_enc;
4744 if ( getint(sfd,&temp))
4745 rf->unicode_enc = temp;
4746 while ( isspace(ch=nlgetc(sfd)));
4747 if ( ch=='S' ) rf->selected = true;
4748 getreal(sfd,&rf->transform[0]);
4749 getreal(sfd,&rf->transform[1]);
4750 getreal(sfd,&rf->transform[2]);
4751 getreal(sfd,&rf->transform[3]);
4752 getreal(sfd,&rf->transform[4]);
4753 getreal(sfd,&rf->transform[5]);
4754 while ( (ch=nlgetc(sfd))==' ');
4755 ungetc(ch,sfd);
4756 if ( isdigit(ch) ) {
4757 getint(sfd,&temp);
4758 rf->use_my_metrics = temp&1;
4759 rf->round_translation_to_grid = (temp&2)?1:0;
4760 rf->point_match = (temp&4)?1:0;
4761 if ( rf->point_match ) {
4762 getsint(sfd,(int16 *) &rf->match_pt_base);
4763 getsint(sfd,(int16 *) &rf->match_pt_ref);
4764 while ( (ch=nlgetc(sfd))==' ');
4765 if ( ch=='O' )
4766 rf->point_match_out_of_date = true;
4767 else
4768 ungetc(ch,sfd);
4769 }
4770 }
4771 return( rf );
4772 }
4773
4774 /* I used to create multiple ligatures by putting ";" between them */
4775 /* that is the component string for "ffi" was "ff i ; f f i" */
4776 /* Now I want to have separate ligature structures for each */
LigaCreateFromOldStyleMultiple(PST1 * liga)4777 static PST1 *LigaCreateFromOldStyleMultiple(PST1 *liga) {
4778 char *pt;
4779 PST1 *new, *last=liga;
4780 while ( (pt = strrchr(liga->pst.u.lig.components,';'))!=NULL ) {
4781 new = chunkalloc(sizeof( PST1 ));
4782 *new = *liga;
4783 new->pst.u.lig.components = copy(pt+1);
4784 last->pst.next = (PST *) new;
4785 last = new;
4786 *pt = '\0';
4787 }
4788 return( last );
4789 }
4790
4791 #ifdef FONTFORGE_CONFIG_CVT_OLD_MAC_FEATURES
4792 static struct { int feature, setting; uint32 tag; } formertags[] = {
4793 { 1, 6, CHR('M','L','O','G') },
4794 { 1, 8, CHR('M','R','E','B') },
4795 { 1, 10, CHR('M','D','L','G') },
4796 { 1, 12, CHR('M','S','L','G') },
4797 { 1, 14, CHR('M','A','L','G') },
4798 { 8, 0, CHR('M','S','W','I') },
4799 { 8, 2, CHR('M','S','W','F') },
4800 { 8, 4, CHR('M','S','L','I') },
4801 { 8, 6, CHR('M','S','L','F') },
4802 { 8, 8, CHR('M','S','N','F') },
4803 { 22, 1, CHR('M','W','I','D') },
4804 { 27, 1, CHR('M','U','C','M') },
4805 { 103, 2, CHR('M','W','I','D') },
4806 { -1, -1, 0xffffffff },
4807 };
4808
CvtOldMacFeature(PST1 * pst)4809 static void CvtOldMacFeature(PST1 *pst) {
4810 int i;
4811
4812 if ( pst->macfeature )
4813 return;
4814 for ( i=0; formertags[i].feature!=-1 ; ++i ) {
4815 if ( pst->tag == formertags[i].tag ) {
4816 pst->macfeature = true;
4817 pst->tag = (formertags[i].feature<<16) | formertags[i].setting;
4818 return;
4819 }
4820 }
4821 }
4822 #endif
4823
SFDSetEncMap(SplineFont * sf,int orig_pos,int enc)4824 static void SFDSetEncMap(SplineFont *sf,int orig_pos,int enc) {
4825 EncMap *map = sf->map;
4826
4827 if ( map==NULL )
4828 return;
4829
4830 if ( orig_pos>=map->backmax ) {
4831 int old = map->backmax;
4832 map->backmax = orig_pos+10;
4833 map->backmap = realloc(map->backmap,map->backmax*sizeof(int));
4834 memset(map->backmap+old,-1,(map->backmax-old)*sizeof(int));
4835 }
4836 if ( map->backmap[orig_pos] == -1 ) /* backmap will not be unique if multiple encodings come from same glyph */
4837 map->backmap[orig_pos] = enc;
4838 if ( enc>=map->encmax ) {
4839 int old = map->encmax;
4840 map->encmax = enc+10;
4841 map->map = realloc(map->map,map->encmax*sizeof(int));
4842 memset(map->map+old,-1,(map->encmax-old)*sizeof(int));
4843 }
4844 if ( enc>=map->enccount )
4845 map->enccount = enc+1;
4846 if ( enc>-1 )
4847 map->map[enc] = orig_pos;
4848 }
4849
SCDefaultInterpolation(SplineChar * sc)4850 static void SCDefaultInterpolation(SplineChar *sc) {
4851 SplineSet *cur;
4852 SplinePoint *sp;
4853 /* We used not to store the dontinterpolate bit. We used to use the */
4854 /* presence or absence of instructions as that flag */
4855
4856 if ( sc->ttf_instrs_len!=0 ) {
4857 for ( cur=sc->layers[ly_fore].splines; cur!=NULL; cur=cur->next ) {
4858 for ( sp=cur->first; ; ) {
4859 if ( sp->ttfindex!=0xffff && SPInterpolate(sp))
4860 sp->dontinterpolate = true;
4861 if ( sp->next==NULL )
4862 break;
4863 sp=sp->next->to;
4864 if ( sp==cur->first )
4865 break;
4866 }
4867 }
4868 }
4869 }
4870
SFDParseMathValueRecord(FILE * sfd,int16 * value,DeviceTable ** devtab)4871 static void SFDParseMathValueRecord(FILE *sfd,int16 *value,DeviceTable **devtab) {
4872 getsint(sfd,value);
4873 *devtab = SFDReadDeviceTable(sfd,NULL);
4874 }
4875
SFDParseGlyphComposition(FILE * sfd,struct glyphvariants * gv,char * tok)4876 static struct glyphvariants *SFDParseGlyphComposition(FILE *sfd,
4877 struct glyphvariants *gv, char *tok) {
4878 int i;
4879
4880 if ( gv==NULL )
4881 gv = chunkalloc(sizeof(struct glyphvariants));
4882 getint(sfd,&gv->part_cnt);
4883 gv->parts = calloc(gv->part_cnt,sizeof(struct gv_part));
4884 for ( i=0; i<gv->part_cnt; ++i ) {
4885 int temp, ch;
4886 getname(sfd,tok);
4887 gv->parts[i].component = copy(tok);
4888 while ( (ch=nlgetc(sfd))==' ' );
4889 if ( ch!='%' ) ungetc(ch,sfd);
4890 getint(sfd,&temp);
4891 gv->parts[i].is_extender = temp;
4892 while ( (ch=nlgetc(sfd))==' ' );
4893 if ( ch!=',' ) ungetc(ch,sfd);
4894 getint(sfd,&temp);
4895 gv->parts[i].startConnectorLength=temp;
4896 while ( (ch=nlgetc(sfd))==' ' );
4897 if ( ch!=',' ) ungetc(ch,sfd);
4898 getint(sfd,&temp);
4899 gv->parts[i].endConnectorLength = temp;
4900 while ( (ch=nlgetc(sfd))==' ' );
4901 if ( ch!=',' ) ungetc(ch,sfd);
4902 getint(sfd,&temp);
4903 gv->parts[i].fullAdvance = temp;
4904 }
4905 return( gv );
4906 }
4907
SFDParseVertexKern(FILE * sfd,struct mathkernvertex * vertex)4908 static void SFDParseVertexKern(FILE *sfd, struct mathkernvertex *vertex) {
4909 int i,ch;
4910
4911 getint(sfd,&vertex->cnt);
4912 vertex->mkd = calloc(vertex->cnt,sizeof(struct mathkerndata));
4913 for ( i=0; i<vertex->cnt; ++i ) {
4914 SFDParseMathValueRecord(sfd,&vertex->mkd[i].height,&vertex->mkd[i].height_adjusts);
4915 while ( (ch=nlgetc(sfd))==' ' );
4916 if ( ch!=EOF && ch!=',' )
4917 ungetc(ch,sfd);
4918 SFDParseMathValueRecord(sfd,&vertex->mkd[i].kern,&vertex->mkd[i].kern_adjusts);
4919 }
4920 }
4921
SFDParseGradient(FILE * sfd,char * tok)4922 static struct gradient *SFDParseGradient(FILE *sfd,char *tok) {
4923 struct gradient *grad = chunkalloc(sizeof(struct gradient));
4924 int ch, i;
4925
4926 getreal(sfd,&grad->start.x);
4927 while ( isspace(ch=nlgetc(sfd)));
4928 if ( ch!=';' ) ungetc(ch,sfd);
4929 getreal(sfd,&grad->start.y);
4930
4931 getreal(sfd,&grad->stop.x);
4932 while ( isspace(ch=nlgetc(sfd)));
4933 if ( ch!=';' ) ungetc(ch,sfd);
4934 getreal(sfd,&grad->stop.y);
4935
4936 getreal(sfd,&grad->radius);
4937
4938 getname(sfd,tok);
4939 for ( i=0; spreads[i]!=NULL; ++i )
4940 if ( strmatch(spreads[i],tok)==0 )
4941 break;
4942 if ( spreads[i]==NULL ) i=0;
4943 grad->sm = i;
4944
4945 getint(sfd,&grad->stop_cnt);
4946 grad->grad_stops = calloc(grad->stop_cnt,sizeof(struct grad_stops));
4947 for ( i=0; i<grad->stop_cnt; ++i ) {
4948 while ( isspace(ch=nlgetc(sfd)));
4949 if ( ch!='{' ) ungetc(ch,sfd);
4950 getreal( sfd, &grad->grad_stops[i].offset );
4951 gethex( sfd, &grad->grad_stops[i].col );
4952 getreal( sfd, &grad->grad_stops[i].opacity );
4953 while ( isspace(ch=nlgetc(sfd)));
4954 if ( ch!='}' ) ungetc(ch,sfd);
4955 }
4956 return( grad );
4957 }
4958
SFDParsePattern(FILE * sfd,char * tok)4959 static struct pattern *SFDParsePattern(FILE *sfd,char *tok) {
4960 struct pattern *pat = chunkalloc(sizeof(struct pattern));
4961 int ch;
4962
4963 getname(sfd,tok);
4964 pat->pattern = copy(tok);
4965
4966 getreal(sfd,&pat->width);
4967 while ( isspace(ch=nlgetc(sfd)));
4968 if ( ch!=';' ) ungetc(ch,sfd);
4969 getreal(sfd,&pat->height);
4970
4971 while ( isspace(ch=nlgetc(sfd)));
4972 if ( ch!='[' ) ungetc(ch,sfd);
4973 getreal(sfd,&pat->transform[0]);
4974 getreal(sfd,&pat->transform[1]);
4975 getreal(sfd,&pat->transform[2]);
4976 getreal(sfd,&pat->transform[3]);
4977 getreal(sfd,&pat->transform[4]);
4978 getreal(sfd,&pat->transform[5]);
4979 while ( isspace(ch=nlgetc(sfd)));
4980 if ( ch!=']' ) ungetc(ch,sfd);
4981 return( pat );
4982 }
4983
4984
SFDConsumeUntil(FILE * sfd,const char ** terminators)4985 static void SFDConsumeUntil( FILE *sfd, const char** terminators ) {
4986
4987 char* line = 0;
4988 while((line = getquotedeol( sfd ))) {
4989 const char** tp = terminators;
4990 for( ; tp && *tp; ++tp ) {
4991 if( !strnmatch( line, *tp, strlen( *tp ))) {
4992 free(line);
4993 return;
4994 }
4995 }
4996 free(line);
4997 }
4998 }
4999
5000 static int orig_pos;
5001
SFDGetKerns(FILE * sfd,SplineChar * sc,char * ttok)5002 void SFDGetKerns( FILE *sfd, SplineChar *sc, char* ttok ) {
5003 struct splinefont * sf = sc->parent;
5004 char tok[2001], ch;
5005 uint32 script = 0;
5006 SplineFont *sli_sf = sf->cidmaster ? sf->cidmaster : sf;
5007
5008 strncpy(tok,ttok,sizeof(tok)-1);
5009 tok[2000]=0;
5010
5011 if( strmatch(tok,"Kerns2:")==0 ||
5012 strmatch(tok,"VKerns2:")==0 ) {
5013 KernPair *kp, *last=NULL;
5014 int isv = *tok=='V';
5015 int off, index;
5016 struct lookup_subtable *sub;
5017 int kernCount = 0;
5018 if ( sf->sfd_version<2 )
5019 LogError(_("Found an new style kerning pair inside a version 1 (or lower) sfd file.\n") );
5020 while ( fscanf(sfd,"%d %d", &index, &off )==2 ) {
5021 sub = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
5022 if ( sub==NULL ) {
5023 LogError(_("KernPair with no subtable name.\n"));
5024 break;
5025 }
5026 kernCount++;
5027 kp = chunkalloc(sizeof(KernPair1));
5028 kp->sc = (SplineChar *) (intpt) index;
5029 kp->kcid = true;
5030 kp->off = off;
5031 kp->subtable = sub;
5032 kp->next = NULL;
5033 while ( (ch=nlgetc(sfd))==' ' );
5034 ungetc(ch,sfd);
5035 if ( ch=='{' ) {
5036 kp->adjust = SFDReadDeviceTable(sfd, NULL);
5037 }
5038 if ( last != NULL )
5039 last->next = kp;
5040 else if ( isv )
5041 sc->vkerns = kp;
5042 else
5043 sc->kerns = kp;
5044 last = kp;
5045 }
5046 if( !kernCount ) {
5047 // printf("SFDGetKerns() have a BLANK KERN\n");
5048 sc->kerns = 0;
5049 }
5050 } else if ( strmatch(tok,"Kerns:")==0 ||
5051 strmatch(tok,"KernsSLI:")==0 ||
5052 strmatch(tok,"KernsSLIF:")==0 ||
5053 strmatch(tok,"VKernsSLIF:")==0 ||
5054 strmatch(tok,"KernsSLIFO:")==0 ||
5055 strmatch(tok,"VKernsSLIFO:")==0 ) {
5056 KernPair1 *kp, *last=NULL;
5057 int index, off, sli, flags=0;
5058 int hassli = (strmatch(tok,"KernsSLI:")==0);
5059 int isv = *tok=='V';
5060 int has_orig = strstr(tok,"SLIFO:")!=NULL;
5061 if ( sf->sfd_version>=2 ) {
5062 IError( "Found an old style kerning pair inside a version 2 (or higher) sfd file." );
5063 exit(1);
5064 }
5065 if ( strmatch(tok,"KernsSLIF:")==0 || strmatch(tok,"KernsSLIFO:")==0 ||
5066 strmatch(tok,"VKernsSLIF:")==0 || strmatch(tok,"VKernsSLIFO:")==0 )
5067 hassli=2;
5068 while ( (hassli==1 && fscanf(sfd,"%d %d %d", &index, &off, &sli )==3) ||
5069 (hassli==2 && fscanf(sfd,"%d %d %d %d", &index, &off, &sli, &flags )==4) ||
5070 (hassli==0 && fscanf(sfd,"%d %d", &index, &off )==2) ) {
5071 if ( !hassli )
5072 sli = SFFindBiggestScriptLangIndex(sli_sf,
5073 script!=0?script:SCScriptFromUnicode(sc),DEFAULT_LANG);
5074 if ( sli>=((SplineFont1 *) sli_sf)->sli_cnt && sli!=SLI_NESTED) {
5075 static int complained=false;
5076 if ( !complained )
5077 IError("'%s' in %s has a script index out of bounds: %d",
5078 isv ? "vkrn" : "kern",
5079 sc->name, sli );
5080 sli = SFFindBiggestScriptLangIndex(sli_sf,
5081 SCScriptFromUnicode(sc),DEFAULT_LANG);
5082 complained = true;
5083 }
5084 kp = chunkalloc(sizeof(KernPair1));
5085 kp->kp.sc = (SplineChar *) (intpt) index;
5086 kp->kp.kcid = has_orig;
5087 kp->kp.off = off;
5088 kp->sli = sli;
5089 kp->flags = flags;
5090 kp->kp.next = NULL;
5091 while ( (ch=nlgetc(sfd))==' ' );
5092 ungetc(ch,sfd);
5093 if ( ch=='{' ) {
5094 kp->kp.adjust = SFDReadDeviceTable(sfd, NULL);
5095 }
5096 if ( last != NULL )
5097 last->kp.next = (KernPair *) kp;
5098 else if ( isv )
5099 sc->vkerns = (KernPair *) kp;
5100 else
5101 sc->kerns = (KernPair *) kp;
5102 last = kp;
5103 }
5104 } else {
5105 return;
5106 }
5107
5108 // we matched something, grab the next top level token to ttok
5109 getname( sfd, ttok );
5110 }
5111
5112
SFDGetPSTs(FILE * sfd,SplineChar * sc,char * ttok)5113 void SFDGetPSTs( FILE *sfd, SplineChar *sc, char* ttok ) {
5114 struct splinefont * sf = sc->parent;
5115 char tok[2001], ch;
5116 int isliga = 0, ispos, issubs, ismult, islcar, ispair, temp;
5117 PST *last = NULL;
5118 uint32 script = 0;
5119 SplineFont *sli_sf = sf->cidmaster ? sf->cidmaster : sf;
5120
5121 strncpy(tok,ttok,sizeof(tok)-1);
5122
5123 if ( strmatch(tok,"Script:")==0 ) {
5124 /* Obsolete. But still used for parsing obsolete ligature/subs tags */
5125 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5126 if ( ch=='\n' || ch=='\r' )
5127 script = 0;
5128 else {
5129 ungetc(ch,sfd);
5130 script = gettag(sfd);
5131 }
5132 } else if ( (ispos = (strmatch(tok,"Position:")==0)) ||
5133 ( ispos = (strmatch(tok,"Position2:")==0)) ||
5134 ( ispair = (strmatch(tok,"PairPos:")==0)) ||
5135 ( ispair = (strmatch(tok,"PairPos2:")==0)) ||
5136 ( islcar = (strmatch(tok,"LCarets:")==0)) ||
5137 ( islcar = (strmatch(tok,"LCarets2:")==0)) ||
5138 ( isliga = (strmatch(tok,"Ligature:")==0)) ||
5139 ( isliga = (strmatch(tok,"Ligature2:")==0)) ||
5140 ( issubs = (strmatch(tok,"Substitution:")==0)) ||
5141 ( issubs = (strmatch(tok,"Substitution2:")==0)) ||
5142 ( ismult = (strmatch(tok,"MultipleSubs:")==0)) ||
5143 ( ismult = (strmatch(tok,"MultipleSubs2:")==0)) ||
5144 strmatch(tok,"AlternateSubs:")==0 ||
5145 strmatch(tok,"AlternateSubs2:")==0 ) {
5146 PST *pst;
5147 int old, type;
5148 type = ispos ? pst_position :
5149 ispair ? pst_pair :
5150 islcar ? pst_lcaret :
5151 isliga ? pst_ligature :
5152 issubs ? pst_substitution :
5153 ismult ? pst_multiple :
5154 pst_alternate;
5155 if ( strchr(tok,'2')!=NULL ) {
5156 old = false;
5157 pst = chunkalloc(sizeof(PST));
5158 if ( type!=pst_lcaret )
5159 pst->subtable = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
5160 } else {
5161 old = true;
5162 pst = chunkalloc(sizeof(PST1));
5163 ((PST1 *) pst)->tag = CHR('l','i','g','a');
5164 ((PST1 *) pst)->script_lang_index = 0xffff;
5165 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5166 if ( isdigit(ch)) {
5167 int temp;
5168 ungetc(ch,sfd);
5169 getint(sfd,&temp);
5170 ((PST1 *) pst)->flags = temp;
5171 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5172 } else
5173 ((PST1 *) pst)->flags = 0 /*PSTDefaultFlags(type,sc)*/;
5174 if ( isdigit(ch)) {
5175 ungetc(ch,sfd);
5176 getusint(sfd,&((PST1 *) pst)->script_lang_index);
5177 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5178 } else
5179 ((PST1 *) pst)->script_lang_index = SFFindBiggestScriptLangIndex(sf,
5180 script!=0?script:SCScriptFromUnicode(sc),DEFAULT_LANG);
5181 if ( ch=='\'' ) {
5182 ungetc(ch,sfd);
5183 ((PST1 *) pst)->tag = gettag(sfd);
5184 } else if ( ch=='<' ) {
5185 getint(sfd,&temp);
5186 ((PST1 *) pst)->tag = temp<<16;
5187 nlgetc(sfd); /* comma */
5188 getint(sfd,&temp);
5189 ((PST1 *) pst)->tag |= temp;
5190 nlgetc(sfd); /* close '>' */
5191 ((PST1 *) pst)->macfeature = true;
5192 } else
5193 ungetc(ch,sfd);
5194 if ( type==pst_lcaret ) {
5195 /* These are meaningless for lcarets, set them to innocuous values */
5196 ((PST1 *) pst)->script_lang_index = SLI_UNKNOWN;
5197 ((PST1 *) pst)->tag = CHR(' ',' ',' ',' ');
5198 } else if ( ((PST1 *) pst)->script_lang_index>=((SplineFont1 *) sli_sf)->sli_cnt && ((PST1 *) pst)->script_lang_index!=SLI_NESTED ) {
5199 static int complained=false;
5200 if ( !complained )
5201 IError("'%c%c%c%c' in %s has a script index out of bounds: %d",
5202 (((PST1 *) pst)->tag>>24), (((PST1 *) pst)->tag>>16)&0xff, (((PST1 *) pst)->tag>>8)&0xff, ((PST1 *) pst)->tag&0xff,
5203 sc->name, ((PST1 *) pst)->script_lang_index );
5204 else
5205 IError( "'%c%c%c%c' in %s has a script index out of bounds: %d\n",
5206 (((PST1 *) pst)->tag>>24), (((PST1 *) pst)->tag>>16)&0xff, (((PST1 *) pst)->tag>>8)&0xff, ((PST1 *) pst)->tag&0xff,
5207 sc->name, ((PST1 *) pst)->script_lang_index );
5208 ((PST1 *) pst)->script_lang_index = SFFindBiggestScriptLangIndex(sli_sf,
5209 SCScriptFromUnicode(sc),DEFAULT_LANG);
5210 complained = true;
5211 }
5212 }
5213 if ( (sf->sfd_version<2)!=old ) {
5214 IError( "Version mixup in PST of sfd file." );
5215 exit(1);
5216 }
5217 if ( last==NULL )
5218 sc->possub = pst;
5219 else
5220 last->next = pst;
5221 last = pst;
5222 pst->type = type;
5223 if ( pst->type==pst_position ) {
5224 fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
5225 &pst->u.pos.xoff, &pst->u.pos.yoff,
5226 &pst->u.pos.h_adv_off, &pst->u.pos.v_adv_off);
5227 pst->u.pos.adjust = SFDReadValDevTab(sfd);
5228 ch = nlgetc(sfd); /* Eat new line */
5229 } else if ( pst->type==pst_pair ) {
5230 getname(sfd,tok);
5231 pst->u.pair.paired = copy(tok);
5232 pst->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
5233 fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
5234 &pst->u.pair.vr[0].xoff, &pst->u.pair.vr[0].yoff,
5235 &pst->u.pair.vr[0].h_adv_off, &pst->u.pair.vr[0].v_adv_off);
5236 pst->u.pair.vr[0].adjust = SFDReadValDevTab(sfd);
5237 fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
5238 &pst->u.pair.vr[1].xoff, &pst->u.pair.vr[1].yoff,
5239 &pst->u.pair.vr[1].h_adv_off, &pst->u.pair.vr[1].v_adv_off);
5240 pst->u.pair.vr[0].adjust = SFDReadValDevTab(sfd);
5241 ch = nlgetc(sfd);
5242 } else if ( pst->type==pst_lcaret ) {
5243 int i;
5244 fscanf( sfd, " %d", &pst->u.lcaret.cnt );
5245 pst->u.lcaret.carets = malloc(pst->u.lcaret.cnt*sizeof(int16));
5246 for ( i=0; i<pst->u.lcaret.cnt; ++i )
5247 fscanf( sfd, " %hd", &pst->u.lcaret.carets[i]);
5248 geteol(sfd,tok);
5249 } else {
5250 geteol(sfd,tok);
5251 pst->u.lig.components = copy(tok); /* it's in the same place for all formats */
5252 if ( isliga ) {
5253 pst->u.lig.lig = sc;
5254 if ( old )
5255 last = (PST *) LigaCreateFromOldStyleMultiple((PST1 *) pst);
5256 }
5257 }
5258 #ifdef FONTFORGE_CONFIG_CVT_OLD_MAC_FEATURES
5259 if ( old )
5260 CvtOldMacFeature((PST1 *) pst);
5261 #endif
5262 } else {
5263 return;
5264 }
5265
5266 // we matched something, grab the next top level token to ttok
5267 getname( sfd, ttok );
5268 }
5269
5270
SFDMoveToNextStartChar(FILE * sfd)5271 char* SFDMoveToNextStartChar( FILE* sfd ) {
5272 char ret[2000];
5273
5274 memset( ret, '\0', 2000 );
5275 char* line = 0;
5276 while((line = getquotedeol( sfd ))) {
5277 if( !strnmatch( line, "StartChar:", strlen( "StartChar:" ))) {
5278 // FIXME: use the getname()/SFDReadUTF7Str() combo
5279 // from SFDGetChar
5280 int len = strlen("StartChar:");
5281 while( line[len] && line[len] == ' ' )
5282 len++;
5283 strcpy( ret, line+len );
5284 free(line);
5285 return copy(ret);
5286 }
5287 free(line);
5288 if(feof( sfd ))
5289 break;
5290
5291 }
5292 return 0;
5293 }
5294
SFDGetChar(FILE * sfd,SplineFont * sf,int had_sf_layer_cnt)5295 static SplineChar *SFDGetChar(FILE *sfd,SplineFont *sf, int had_sf_layer_cnt) {
5296 SplineChar *sc;
5297 char tok[2000], ch;
5298 RefChar *lastr=NULL, *ref;
5299 ImageList *lasti=NULL, *img;
5300 AnchorPoint *lastap = NULL;
5301 GuidelineSet *lastgl = NULL;
5302 int isliga = 0, ispos, issubs, ismult, islcar, ispair, temp, i;
5303 PST *last = NULL;
5304 uint32 script = 0;
5305 int current_layer = ly_fore;
5306 int multilayer = sf->multilayer;
5307 int had_old_dstems = false;
5308 SplineFont *sli_sf = sf->cidmaster ? sf->cidmaster : sf;
5309 struct altuni *altuni;
5310 int oldback = false;
5311
5312 if ( getname(sfd,tok)!=1 )
5313 return( NULL );
5314 if ( strcmp(tok,"StartChar:")!=0 )
5315 return( NULL );
5316 while ( isspace(ch=nlgetc(sfd)));
5317 ungetc(ch,sfd);
5318 sc = SFSplineCharCreate(sf);
5319 if ( ch!='"' ) {
5320 if ( getname(sfd,tok)!=1 ) {
5321 SplineCharFree(sc);
5322 return( NULL );
5323 }
5324 sc->name = copy(tok);
5325 } else {
5326 sc->name = SFDReadUTF7Str(sfd);
5327 if ( sc->name==NULL ) {
5328 SplineCharFree(sc);
5329 return( NULL );
5330 }
5331 }
5332 sc->vwidth = sf->ascent+sf->descent;
5333 sc->parent = sf;
5334 while ( 1 ) {
5335 if ( getname(sfd,tok)!=1 ) {
5336 SplineCharFree(sc);
5337 return( NULL );
5338 }
5339 if ( strmatch(tok,"Encoding:")==0 ) {
5340 int enc;
5341 getint(sfd,&enc);
5342 getint(sfd,&sc->unicodeenc);
5343 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5344 ungetc(ch,sfd);
5345 if ( ch!='\n' && ch!='\r' ) {
5346 getint(sfd,&sc->orig_pos);
5347 if ( sc->orig_pos==65535 )
5348 sc->orig_pos = orig_pos++;
5349 /* An old mark meaning: "I don't know" */
5350 if ( sc->orig_pos<sf->glyphcnt && sf->glyphs[sc->orig_pos]!=NULL )
5351 sc->orig_pos = sf->glyphcnt;
5352 if ( sc->orig_pos>=sf->glyphcnt ) {
5353 if ( sc->orig_pos>=sf->glyphmax )
5354 sf->glyphs = realloc(sf->glyphs,(sf->glyphmax = sc->orig_pos+10)*sizeof(SplineChar *));
5355 memset(sf->glyphs+sf->glyphcnt,0,(sc->orig_pos+1-sf->glyphcnt)*sizeof(SplineChar *));
5356 sf->glyphcnt = sc->orig_pos+1;
5357 }
5358 if ( sc->orig_pos+1 > orig_pos )
5359 orig_pos = sc->orig_pos+1;
5360 } else if ( sf->cidmaster!=NULL ) { /* In cid fonts the orig_pos is just the cid */
5361 sc->orig_pos = enc;
5362 } else {
5363 sc->orig_pos = orig_pos++;
5364 }
5365 SFDSetEncMap(sf,sc->orig_pos,enc);
5366 } else if ( strmatch(tok,"AltUni:")==0 ) {
5367 int uni;
5368 while ( getint(sfd,&uni)==1 ) {
5369 altuni = chunkalloc(sizeof(struct altuni));
5370 altuni->unienc = uni;
5371 altuni->vs = -1;
5372 altuni->fid = 0;
5373 altuni->next = sc->altuni;
5374 sc->altuni = altuni;
5375 }
5376 } else if ( strmatch(tok,"AltUni2:")==0 ) {
5377 uint32 uni[3];
5378 while ( gethexints(sfd,uni,3) ) {
5379 altuni = chunkalloc(sizeof(struct altuni));
5380 altuni->unienc = uni[0];
5381 altuni->vs = uni[1];
5382 altuni->fid = uni[2];
5383 altuni->next = sc->altuni;
5384 sc->altuni = altuni;
5385 }
5386 } else if ( strmatch(tok,"OldEncoding:")==0 ) {
5387 int old_enc; /* Obsolete info */
5388 getint(sfd,&old_enc);
5389 } else if ( strmatch(tok,"Script:")==0 ) {
5390 /* Obsolete. But still used for parsing obsolete ligature/subs tags */
5391 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5392 if ( ch=='\n' || ch=='\r' )
5393 script = 0;
5394 else {
5395 ungetc(ch,sfd);
5396 script = gettag(sfd);
5397 }
5398 } else if ( strmatch(tok,"GlifName:")==0 ) {
5399 while ( isspace(ch=nlgetc(sfd)));
5400 ungetc(ch,sfd);
5401 if ( ch!='"' ) {
5402 if ( getname(sfd,tok)!=1 ) {
5403 LogError(_("Invalid glif name.\n"));
5404 }
5405 sc->glif_name = copy(tok);
5406 } else {
5407 sc->glif_name = SFDReadUTF7Str(sfd);
5408 if ( sc->glif_name==NULL ) {
5409 LogError(_("Invalid glif name.\n"));
5410 }
5411 }
5412 } else if ( strmatch(tok,"Width:")==0 ) {
5413 getsint(sfd,&sc->width);
5414 } else if ( strmatch(tok,"VWidth:")==0 ) {
5415 getsint(sfd,&sc->vwidth);
5416 } else if ( strmatch(tok,"GlyphClass:")==0 ) {
5417 getint(sfd,&temp);
5418 sc->glyph_class = temp;
5419 } else if ( strmatch(tok,"UnlinkRmOvrlpSave:")==0 ) {
5420 getint(sfd,&temp);
5421 sc->unlink_rm_ovrlp_save_undo = temp;
5422 } else if ( strmatch(tok,"InSpiro:")==0 ) {
5423 getint(sfd,&temp);
5424 sc->inspiro = temp;
5425 } else if ( strmatch(tok,"LigCaretCntFixed:")==0 ) {
5426 getint(sfd,&temp);
5427 sc->lig_caret_cnt_fixed = temp;
5428 } else if ( strmatch(tok,"Flags:")==0 ) {
5429 while ( isspace(ch=nlgetc(sfd)) && ch!='\n' && ch!='\r');
5430 while ( ch!='\n' && ch!='\r' ) {
5431 if ( ch=='H' ) sc->changedsincelasthinted=true;
5432 else if ( ch=='M' ) sc->manualhints = true;
5433 else if ( ch=='W' ) sc->widthset = true;
5434 else if ( ch=='O' ) sc->wasopen = true;
5435 else if ( ch=='I' ) sc->instructions_out_of_date = true;
5436 ch = nlgetc(sfd);
5437 }
5438 if ( sf->multilayer || sf->onlybitmaps || sf->strokedfont || sc->layers[ly_fore].order2 )
5439 sc->changedsincelasthinted = false;
5440 } else if ( strmatch(tok,"TeX:")==0 ) {
5441 getsint(sfd,&sc->tex_height);
5442 getsint(sfd,&sc->tex_depth);
5443 while ( isspace(ch=nlgetc(sfd)) && ch!='\n' && ch!='\r');
5444 ungetc(ch,sfd);
5445 if ( ch!='\n' && ch!='\r' ) {
5446 int16 old_tex;
5447 /* Used to store two extra values here */
5448 getsint(sfd,&old_tex);
5449 getsint(sfd,&old_tex);
5450 if ( sc->tex_height==0 && sc->tex_depth==0 ) /* Fixup old bug */
5451 sc->tex_height = sc->tex_depth = TEX_UNDEF;
5452 }
5453 } else if ( strmatch(tok,"ItalicCorrection:")==0 ) {
5454 SFDParseMathValueRecord(sfd,&sc->italic_correction,&sc->italic_adjusts);
5455 } else if ( strmatch(tok,"TopAccentHorizontal:")==0 ) {
5456 SFDParseMathValueRecord(sfd,&sc->top_accent_horiz,&sc->top_accent_adjusts);
5457 } else if ( strmatch(tok,"GlyphCompositionVerticalIC:")==0 ) {
5458 if ( sc->vert_variants==NULL )
5459 sc->vert_variants = chunkalloc(sizeof(struct glyphvariants));
5460 SFDParseMathValueRecord(sfd,&sc->vert_variants->italic_correction,&sc->vert_variants->italic_adjusts);
5461 } else if ( strmatch(tok,"GlyphCompositionHorizontalIC:")==0 ) {
5462 if ( sc->horiz_variants==NULL )
5463 sc->horiz_variants = chunkalloc(sizeof(struct glyphvariants));
5464 SFDParseMathValueRecord(sfd,&sc->horiz_variants->italic_correction,&sc->horiz_variants->italic_adjusts);
5465 } else if ( strmatch(tok,"IsExtendedShape:")==0 ) {
5466 int temp;
5467 getint(sfd,&temp);
5468 sc->is_extended_shape = temp;
5469 } else if ( strmatch(tok,"GlyphVariantsVertical:")==0 ) {
5470 if ( sc->vert_variants==NULL )
5471 sc->vert_variants = chunkalloc(sizeof(struct glyphvariants));
5472 geteol(sfd,tok);
5473 sc->vert_variants->variants = copy(tok);
5474 } else if ( strmatch(tok,"GlyphVariantsHorizontal:")==0 ) {
5475 if ( sc->horiz_variants==NULL )
5476 sc->horiz_variants = chunkalloc(sizeof(struct glyphvariants));
5477 geteol(sfd,tok);
5478 sc->horiz_variants->variants = copy(tok);
5479 } else if ( strmatch(tok,"GlyphCompositionVertical:")==0 ) {
5480 sc->vert_variants = SFDParseGlyphComposition(sfd, sc->vert_variants,tok);
5481 } else if ( strmatch(tok,"GlyphCompositionHorizontal:")==0 ) {
5482 sc->horiz_variants = SFDParseGlyphComposition(sfd, sc->horiz_variants,tok);
5483 } else if ( strmatch(tok,"TopRightVertex:")==0 ) {
5484 if ( sc->mathkern==NULL )
5485 sc->mathkern = chunkalloc(sizeof(struct mathkern));
5486 SFDParseVertexKern(sfd, &sc->mathkern->top_right);
5487 } else if ( strmatch(tok,"TopLeftVertex:")==0 ) {
5488 if ( sc->mathkern==NULL )
5489 sc->mathkern = chunkalloc(sizeof(struct mathkern));
5490 SFDParseVertexKern(sfd, &sc->mathkern->top_left);
5491 } else if ( strmatch(tok,"BottomRightVertex:")==0 ) {
5492 if ( sc->mathkern==NULL )
5493 sc->mathkern = chunkalloc(sizeof(struct mathkern));
5494 SFDParseVertexKern(sfd, &sc->mathkern->bottom_right);
5495 } else if ( strmatch(tok,"BottomLeftVertex:")==0 ) {
5496 if ( sc->mathkern==NULL )
5497 sc->mathkern = chunkalloc(sizeof(struct mathkern));
5498 SFDParseVertexKern(sfd, &sc->mathkern->bottom_left);
5499 #if HANYANG
5500 } else if ( strmatch(tok,"CompositionUnit:")==0 ) {
5501 getsint(sfd,&sc->jamo);
5502 getsint(sfd,&sc->varient);
5503 sc->compositionunit = true;
5504 #endif
5505 } else if ( strmatch(tok,"HStem:")==0 ) {
5506 sc->hstem = SFDReadHints(sfd);
5507 sc->hconflicts = StemListAnyConflicts(sc->hstem);
5508 } else if ( strmatch(tok,"VStem:")==0 ) {
5509 sc->vstem = SFDReadHints(sfd);
5510 sc->vconflicts = StemListAnyConflicts(sc->vstem);
5511 } else if ( strmatch(tok,"DStem:")==0 ) {
5512 sc->dstem = SFDReadDHints( sc->parent,sfd,true );
5513 had_old_dstems = true;
5514 } else if ( strmatch(tok,"DStem2:")==0 ) {
5515 sc->dstem = SFDReadDHints( sc->parent,sfd,false );
5516 } else if ( strmatch(tok,"CounterMasks:")==0 ) {
5517 getsint(sfd,&sc->countermask_cnt);
5518 sc->countermasks = calloc(sc->countermask_cnt,sizeof(HintMask));
5519 for ( i=0; i<sc->countermask_cnt; ++i ) {
5520 int ch;
5521 while ( (ch=nlgetc(sfd))==' ' );
5522 ungetc(ch,sfd);
5523 SFDGetHintMask(sfd,&sc->countermasks[i]);
5524 }
5525 } else if ( strmatch(tok,"AnchorPoint:")==0 ) {
5526 lastap = SFDReadAnchorPoints(sfd,sc,&sc->anchor,lastap);
5527 } else if ( strmatch(tok,"Fore")==0 ) {
5528 while ( isspace(ch = nlgetc(sfd)));
5529 ungetc(ch,sfd);
5530 if ( ch!='I' && ch!='R' && ch!='S' && ch!='V' && ch!=' ' && ch!='\n' &&
5531 !PeekMatch(sfd, "Pickled") && !PeekMatch(sfd, "EndChar") &&
5532 !PeekMatch(sfd, "Fore") && !PeekMatch(sfd, "Back") && !PeekMatch(sfd, "Layer") ) {
5533 /* Old format, without a SplineSet token */
5534 sc->layers[ly_fore].splines = SFDGetSplineSet(sfd,sc->layers[ly_fore].order2);
5535 }
5536 current_layer = ly_fore;
5537 lastgl = NULL;
5538 } else if ( strmatch(tok,"MinimumDistance:")==0 ) {
5539 SFDGetMinimumDistances(sfd,sc);
5540 } else if ( strmatch(tok,"Validated:")==0 ) {
5541 getsint(sfd,(int16 *) &sc->layers[current_layer].validation_state);
5542 } else if ( strmatch(tok,"Back")==0 ) {
5543 while ( isspace(ch=nlgetc(sfd)));
5544 ungetc(ch,sfd);
5545 if ( ch!='I' && ch!='R' && ch!='S' && ch!='V' && ch!=' ' && ch!='\n' &&
5546 !PeekMatch(sfd, "Pickled") && !PeekMatch(sfd, "EndChar") &&
5547 !PeekMatch(sfd, "Fore") && !PeekMatch(sfd, "Back") && !PeekMatch(sfd, "Layer") ) {
5548 /* Old format, without a SplineSet token */
5549 sc->layers[ly_back].splines = SFDGetSplineSet(sfd,sc->layers[ly_back].order2);
5550 oldback = true;
5551 }
5552 current_layer = ly_back;
5553 lastgl = NULL;
5554 } else if ( strmatch(tok,"LayerCount:")==0 ) {
5555 getint(sfd,&temp);
5556 if ( temp>sc->layer_cnt ) {
5557 sc->layers = realloc(sc->layers,temp*sizeof(Layer));
5558 memset(sc->layers+sc->layer_cnt,0,(temp-sc->layer_cnt)*sizeof(Layer));
5559 }
5560 sc->layer_cnt = temp;
5561 current_layer = ly_fore;
5562 } else if ( strmatch(tok,"Layer:")==0 ) {
5563 int layer;
5564 int dofill, dostroke, fillfirst, linejoin, linecap;
5565 uint32 fillcol, strokecol;
5566 real fillopacity, strokeopacity, strokewidth, trans[4];
5567 DashType dashes[DASH_MAX];
5568 int i;
5569 getint(sfd,&layer);
5570 if ( layer>=sc->layer_cnt ) {
5571 sc->layers = realloc(sc->layers,(layer+1)*sizeof(Layer));
5572 memset(sc->layers+sc->layer_cnt,0,(layer+1-sc->layer_cnt)*sizeof(Layer));
5573 }
5574 if ( sc->parent->multilayer ) {
5575 getint(sfd,&dofill);
5576 getint(sfd,&dostroke);
5577 getint(sfd,&fillfirst);
5578 gethex(sfd,&fillcol);
5579 getreal(sfd,&fillopacity);
5580 gethex(sfd,&strokecol);
5581 getreal(sfd,&strokeopacity);
5582 getreal(sfd,&strokewidth);
5583 getname(sfd,tok);
5584 for ( i=0; joins[i]!=NULL; ++i )
5585 if ( strmatch(joins[i],tok)==0 )
5586 break;
5587 if ( joins[i]==NULL ) --i;
5588 linejoin = i;
5589 getname(sfd,tok);
5590 for ( i=0; caps[i]!=NULL; ++i )
5591 if ( strmatch(caps[i],tok)==0 )
5592 break;
5593 if ( caps[i]==NULL ) --i;
5594 linecap = i;
5595 while ( (ch=nlgetc(sfd))==' ' || ch=='[' );
5596 ungetc(ch,sfd);
5597 getreal(sfd,&trans[0]);
5598 getreal(sfd,&trans[1]);
5599 getreal(sfd,&trans[2]);
5600 getreal(sfd,&trans[3]);
5601 while ( (ch=nlgetc(sfd))==' ' || ch==']' );
5602 if ( ch=='[' ) {
5603 for ( i=0;; ++i ) { int temp;
5604 if ( !getint(sfd,&temp) )
5605 break;
5606 else if ( i<DASH_MAX )
5607 dashes[i] = temp;
5608 }
5609 if ( i<DASH_MAX )
5610 dashes[i] = 0;
5611 } else {
5612 ungetc(ch,sfd);
5613 memset(dashes,0,sizeof(dashes));
5614 }
5615 sc->layers[layer].dofill = dofill;
5616 sc->layers[layer].dostroke = dostroke;
5617 sc->layers[layer].fillfirst = fillfirst;
5618 sc->layers[layer].fill_brush.col = fillcol;
5619 sc->layers[layer].fill_brush.opacity = fillopacity;
5620 sc->layers[layer].stroke_pen.brush.col = strokecol;
5621 sc->layers[layer].stroke_pen.brush.opacity = strokeopacity;
5622 sc->layers[layer].stroke_pen.width = strokewidth;
5623 sc->layers[layer].stroke_pen.linejoin = linejoin;
5624 sc->layers[layer].stroke_pen.linecap = linecap;
5625 memcpy(sc->layers[layer].stroke_pen.dashes,dashes,sizeof(dashes));
5626 memcpy(sc->layers[layer].stroke_pen.trans,trans,sizeof(trans));
5627 }
5628 current_layer = layer;
5629 lasti = NULL;
5630 lastr = NULL;
5631 lastgl = NULL;
5632 } else if ( strmatch(tok,"FillGradient:")==0 ) {
5633 sc->layers[current_layer].fill_brush.gradient = SFDParseGradient(sfd,tok);
5634 } else if ( strmatch(tok,"FillPattern:")==0 ) {
5635 sc->layers[current_layer].fill_brush.pattern = SFDParsePattern(sfd,tok);
5636 } else if ( strmatch(tok,"StrokeGradient:")==0 ) {
5637 sc->layers[current_layer].stroke_pen.brush.gradient = SFDParseGradient(sfd,tok);
5638 } else if ( strmatch(tok,"StrokePattern:")==0 ) {
5639 sc->layers[current_layer].stroke_pen.brush.pattern = SFDParsePattern(sfd,tok);
5640 } else if ( strmatch(tok,"UndoRedoHistory")==0 ) {
5641
5642 getname(sfd,tok);
5643 if ( !strmatch(tok,"Layer:") ) {
5644 int layer;
5645 getint(sfd,&layer);
5646 }
5647
5648 int limit;
5649 Undoes *undo = 0;
5650 struct undoes *last = 0;
5651
5652 getname(sfd,tok);
5653 if ( !strmatch(tok,"Undoes") ) {
5654 undo = 0;
5655 limit = UndoRedoLimitToLoad;
5656 last = sc->layers[current_layer].undoes;
5657 while((undo = SFDGetUndo( sfd, sc, "UndoOperation", current_layer )))
5658 {
5659 // push to back
5660 if( last ) last->next = undo;
5661 else sc->layers[current_layer].undoes = undo;
5662 last = undo;
5663
5664 if( limit != -1 ) {
5665 limit--;
5666 if( limit <= 0 ) {
5667 // we have hit our load limit, so lets just chuck everything away
5668 // until we hit the EndUndoes/EndRedoes magic line and then start
5669 // actually processing again.
5670 const char* terminators[] = { "EndUndoes", "EndRedoes", 0 };
5671 SFDConsumeUntil( sfd, terminators );
5672 }
5673 }
5674 }
5675 }
5676 getname(sfd,tok);
5677 if ( !strmatch(tok,"Redoes") ) {
5678 undo = 0;
5679 limit = UndoRedoLimitToLoad;
5680 last = sc->layers[current_layer].redoes;
5681 while((undo = SFDGetUndo( sfd, sc, "RedoOperation", current_layer )))
5682 {
5683 // push to back
5684 if( last ) last->next = undo;
5685 else sc->layers[current_layer].redoes = undo;
5686 last = undo;
5687
5688 if( limit != -1 ) {
5689 limit--;
5690 if( limit <= 0 ) {
5691 // we have hit our load limit, so lets just chuck everything away
5692 // until we hit the EndUndoes/EndRedoes magic line and then start
5693 // actually processing again.
5694 const char* terminators[] = { "EndUndoes", "EndRedoes", 0 };
5695 SFDConsumeUntil( sfd, terminators );
5696 }
5697 }
5698 }
5699 }
5700 } else if ( strmatch(tok,"SplineSet")==0 ) {
5701 sc->layers[current_layer].splines = SFDGetSplineSet(sfd,sc->layers[current_layer].order2);
5702 } else if ( strmatch(tok,"Guideline:")==0 ) {
5703 lastgl = SFDReadGuideline(sfd, &sc->layers[current_layer].guidelines, lastgl);
5704 } else if ( strmatch(tok,"Ref:")==0 || strmatch(tok,"Refer:")==0 ) {
5705 /* I should be depending on the version number here, but I made */
5706 /* a mistake and bumped the version too late. So the version is */
5707 /* not an accurate mark, but the presence of a LayerCount keyword*/
5708 /* in the font is an good mark. Before the LayerCount was added */
5709 /* (version 2) only the foreground layer could have references */
5710 /* after that (eventually version 3) any layer could. */
5711 if ( oldback || !had_sf_layer_cnt ) current_layer = ly_fore;
5712 ref = SFDGetRef(sfd,strmatch(tok,"Ref:")==0);
5713 if ( sc->layers[current_layer].refs==NULL )
5714 sc->layers[current_layer].refs = ref;
5715 else
5716 lastr->next = ref;
5717 lastr = ref;
5718 } else if ( strmatch(tok,"Image:")==0 ) {
5719 int ly = current_layer;
5720 if ( !multilayer && !sc->layers[ly].background ) ly = ly_back;
5721 img = SFDGetImage(sfd);
5722 if (img != NULL) {
5723 if ( sc->layers[ly].images==NULL )
5724 sc->layers[ly].images = img;
5725 else
5726 lasti->next = img;
5727 lasti = img;
5728 }
5729 } else if ( strmatch(tok,"Image2:")==0 ) {
5730 #ifndef _NO_LIBPNG
5731 enum MIME mime = SFDGetImage2MIME(sfd);
5732 if (mime == PNG) {
5733 int ly = current_layer;
5734 if ( !multilayer && !sc->layers[ly].background ) ly = ly_back;
5735 img = SFDGetImagePNG(sfd);
5736 if (img != NULL) {
5737 if ( sc->layers[ly].images==NULL )
5738 sc->layers[ly].images = img;
5739 else
5740 lasti->next = img;
5741 lasti = img;
5742 }
5743 } else
5744 #endif
5745 {
5746 LogError(_("Image2 skipped as it uses an unsupported image type"));
5747 const char* im2_terminator[] = { "EndImage2", 0 };
5748 SFDConsumeUntil(sfd, im2_terminator);
5749 }
5750 } else if ( strmatch(tok,"PickledData:")==0 ) {
5751 if (current_layer < sc->layer_cnt) {
5752 sc->layers[current_layer].python_persistent = SFDUnPickle(sfd, 0);
5753 sc->layers[current_layer].python_persistent_has_lists = 0;
5754 }
5755 } else if ( strmatch(tok,"PickledDataWithLists:")==0 ) {
5756 if (current_layer < sc->layer_cnt) {
5757 sc->layers[current_layer].python_persistent = SFDUnPickle(sfd, 1);
5758 sc->layers[current_layer].python_persistent_has_lists = 1;
5759 }
5760 } else if ( strmatch(tok,"OrigType1:")==0 ) { /* Accept, slurp, ignore contents */
5761 SFDGetType1(sfd);
5762 } else if ( strmatch(tok,"TtfInstrs:")==0 ) { /* Binary format */
5763 SFDGetTtfInstrs(sfd,sc);
5764 } else if ( strmatch(tok,"TtInstrs:")==0 ) { /* ASCII format */
5765 SFDGetTtInstrs(sfd,sc);
5766 } else if ( strmatch(tok,"Kerns2:")==0 ||
5767 strmatch(tok,"VKerns2:")==0 ) {
5768 KernPair *kp, *last=NULL;
5769 int isv = *tok=='V';
5770 int off, index;
5771 struct lookup_subtable *sub;
5772
5773 if ( sf->sfd_version<2 )
5774 LogError(_("Found an new style kerning pair inside a version 1 (or lower) sfd file.\n") );
5775 while ( fscanf(sfd,"%d %d", &index, &off )==2 ) {
5776 sub = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
5777 if ( sub==NULL ) {
5778 LogError(_("KernPair with no subtable name.\n"));
5779 break;
5780 }
5781 kp = chunkalloc(sizeof(KernPair1));
5782 kp->sc = (SplineChar *) (intpt) index;
5783 kp->kcid = true;
5784 kp->off = off;
5785 kp->subtable = sub;
5786 kp->next = NULL;
5787 while ( (ch=nlgetc(sfd))==' ' );
5788 ungetc(ch,sfd);
5789 if ( ch=='{' ) {
5790 kp->adjust = SFDReadDeviceTable(sfd, NULL);
5791 }
5792 if ( last != NULL )
5793 last->next = kp;
5794 else if ( isv )
5795 sc->vkerns = kp;
5796 else
5797 sc->kerns = kp;
5798 last = kp;
5799 }
5800 } else if ( strmatch(tok,"Kerns:")==0 ||
5801 strmatch(tok,"KernsSLI:")==0 ||
5802 strmatch(tok,"KernsSLIF:")==0 ||
5803 strmatch(tok,"VKernsSLIF:")==0 ||
5804 strmatch(tok,"KernsSLIFO:")==0 ||
5805 strmatch(tok,"VKernsSLIFO:")==0 ) {
5806 KernPair1 *kp, *last=NULL;
5807 int index, off, sli, flags=0;
5808 int hassli = (strmatch(tok,"KernsSLI:")==0);
5809 int isv = *tok=='V';
5810 int has_orig = strstr(tok,"SLIFO:")!=NULL;
5811 if ( sf->sfd_version>=2 ) {
5812 IError( "Found an old style kerning pair inside a version 2 (or higher) sfd file." );
5813 exit(1);
5814 }
5815 if ( strmatch(tok,"KernsSLIF:")==0 || strmatch(tok,"KernsSLIFO:")==0 ||
5816 strmatch(tok,"VKernsSLIF:")==0 || strmatch(tok,"VKernsSLIFO:")==0 )
5817 hassli=2;
5818 while ( (hassli==1 && fscanf(sfd,"%d %d %d", &index, &off, &sli )==3) ||
5819 (hassli==2 && fscanf(sfd,"%d %d %d %d", &index, &off, &sli, &flags )==4) ||
5820 (hassli==0 && fscanf(sfd,"%d %d", &index, &off )==2) ) {
5821 if ( !hassli )
5822 sli = SFFindBiggestScriptLangIndex(sli_sf,
5823 script!=0?script:SCScriptFromUnicode(sc),DEFAULT_LANG);
5824 if ( sli>=((SplineFont1 *) sli_sf)->sli_cnt && sli!=SLI_NESTED) {
5825 static int complained=false;
5826 if ( !complained )
5827 IError("'%s' in %s has a script index out of bounds: %d",
5828 isv ? "vkrn" : "kern",
5829 sc->name, sli );
5830 sli = SFFindBiggestScriptLangIndex(sli_sf,
5831 SCScriptFromUnicode(sc),DEFAULT_LANG);
5832 complained = true;
5833 }
5834 kp = chunkalloc(sizeof(KernPair1));
5835 kp->kp.sc = (SplineChar *) (intpt) index;
5836 kp->kp.kcid = has_orig;
5837 kp->kp.off = off;
5838 kp->sli = sli;
5839 kp->flags = flags;
5840 kp->kp.next = NULL;
5841 while ( (ch=nlgetc(sfd))==' ' );
5842 ungetc(ch,sfd);
5843 if ( ch=='{' ) {
5844 kp->kp.adjust = SFDReadDeviceTable(sfd, NULL);
5845 }
5846 if ( last != NULL )
5847 last->kp.next = (KernPair *) kp;
5848 else if ( isv )
5849 sc->vkerns = (KernPair *) kp;
5850 else
5851 sc->kerns = (KernPair *) kp;
5852 last = kp;
5853 }
5854 } else if ( (ispos = (strmatch(tok,"Position:")==0)) ||
5855 ( ispos = (strmatch(tok,"Position2:")==0)) ||
5856 ( ispair = (strmatch(tok,"PairPos:")==0)) ||
5857 ( ispair = (strmatch(tok,"PairPos2:")==0)) ||
5858 ( islcar = (strmatch(tok,"LCarets:")==0)) ||
5859 ( islcar = (strmatch(tok,"LCarets2:")==0)) ||
5860 ( isliga = (strmatch(tok,"Ligature:")==0)) ||
5861 ( isliga = (strmatch(tok,"Ligature2:")==0)) ||
5862 ( issubs = (strmatch(tok,"Substitution:")==0)) ||
5863 ( issubs = (strmatch(tok,"Substitution2:")==0)) ||
5864 ( ismult = (strmatch(tok,"MultipleSubs:")==0)) ||
5865 ( ismult = (strmatch(tok,"MultipleSubs2:")==0)) ||
5866 strmatch(tok,"AlternateSubs:")==0 ||
5867 strmatch(tok,"AlternateSubs2:")==0 ) {
5868 PST *pst;
5869 int old, type;
5870 type = ispos ? pst_position :
5871 ispair ? pst_pair :
5872 islcar ? pst_lcaret :
5873 isliga ? pst_ligature :
5874 issubs ? pst_substitution :
5875 ismult ? pst_multiple :
5876 pst_alternate;
5877 if ( strchr(tok,'2')!=NULL ) {
5878 old = false;
5879 pst = chunkalloc(sizeof(PST));
5880 if ( type!=pst_lcaret )
5881 pst->subtable = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
5882 } else {
5883 old = true;
5884 pst = chunkalloc(sizeof(PST1));
5885 ((PST1 *) pst)->tag = CHR('l','i','g','a');
5886 ((PST1 *) pst)->script_lang_index = 0xffff;
5887 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5888 if ( isdigit(ch)) {
5889 int temp;
5890 ungetc(ch,sfd);
5891 getint(sfd,&temp);
5892 ((PST1 *) pst)->flags = temp;
5893 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5894 } else
5895 ((PST1 *) pst)->flags = 0 /*PSTDefaultFlags(type,sc)*/;
5896 if ( isdigit(ch)) {
5897 ungetc(ch,sfd);
5898 getusint(sfd,&((PST1 *) pst)->script_lang_index);
5899 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
5900 } else
5901 ((PST1 *) pst)->script_lang_index = SFFindBiggestScriptLangIndex(sf,
5902 script!=0?script:SCScriptFromUnicode(sc),DEFAULT_LANG);
5903 if ( ch=='\'' ) {
5904 ungetc(ch,sfd);
5905 ((PST1 *) pst)->tag = gettag(sfd);
5906 } else if ( ch=='<' ) {
5907 getint(sfd,&temp);
5908 ((PST1 *) pst)->tag = temp<<16;
5909 nlgetc(sfd); /* comma */
5910 getint(sfd,&temp);
5911 ((PST1 *) pst)->tag |= temp;
5912 nlgetc(sfd); /* close '>' */
5913 ((PST1 *) pst)->macfeature = true;
5914 } else
5915 ungetc(ch,sfd);
5916 if ( type==pst_lcaret ) {
5917 /* These are meaningless for lcarets, set them to innocuous values */
5918 ((PST1 *) pst)->script_lang_index = SLI_UNKNOWN;
5919 ((PST1 *) pst)->tag = CHR(' ',' ',' ',' ');
5920 } else if ( ((PST1 *) pst)->script_lang_index>=((SplineFont1 *) sli_sf)->sli_cnt && ((PST1 *) pst)->script_lang_index!=SLI_NESTED ) {
5921 static int complained=false;
5922 if ( !complained )
5923 IError("'%c%c%c%c' in %s has a script index out of bounds: %d",
5924 (((PST1 *) pst)->tag>>24), (((PST1 *) pst)->tag>>16)&0xff, (((PST1 *) pst)->tag>>8)&0xff, ((PST1 *) pst)->tag&0xff,
5925 sc->name, ((PST1 *) pst)->script_lang_index );
5926 else
5927 IError( "'%c%c%c%c' in %s has a script index out of bounds: %d\n",
5928 (((PST1 *) pst)->tag>>24), (((PST1 *) pst)->tag>>16)&0xff, (((PST1 *) pst)->tag>>8)&0xff, ((PST1 *) pst)->tag&0xff,
5929 sc->name, ((PST1 *) pst)->script_lang_index );
5930 ((PST1 *) pst)->script_lang_index = SFFindBiggestScriptLangIndex(sli_sf,
5931 SCScriptFromUnicode(sc),DEFAULT_LANG);
5932 complained = true;
5933 }
5934 }
5935 if ( (sf->sfd_version<2)!=old ) {
5936 IError( "Version mixup in PST of sfd file." );
5937 exit(1);
5938 }
5939 if ( last==NULL )
5940 sc->possub = pst;
5941 else
5942 last->next = pst;
5943 last = pst;
5944 pst->type = type;
5945 if ( pst->type==pst_position ) {
5946 fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
5947 &pst->u.pos.xoff, &pst->u.pos.yoff,
5948 &pst->u.pos.h_adv_off, &pst->u.pos.v_adv_off);
5949 pst->u.pos.adjust = SFDReadValDevTab(sfd);
5950 ch = nlgetc(sfd); /* Eat new line */
5951 } else if ( pst->type==pst_pair ) {
5952 getname(sfd,tok);
5953 pst->u.pair.paired = copy(tok);
5954 pst->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
5955 fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
5956 &pst->u.pair.vr[0].xoff, &pst->u.pair.vr[0].yoff,
5957 &pst->u.pair.vr[0].h_adv_off, &pst->u.pair.vr[0].v_adv_off);
5958 pst->u.pair.vr[0].adjust = SFDReadValDevTab(sfd);
5959 fscanf( sfd, " dx=%hd dy=%hd dh=%hd dv=%hd",
5960 &pst->u.pair.vr[1].xoff, &pst->u.pair.vr[1].yoff,
5961 &pst->u.pair.vr[1].h_adv_off, &pst->u.pair.vr[1].v_adv_off);
5962 pst->u.pair.vr[0].adjust = SFDReadValDevTab(sfd);
5963 ch = nlgetc(sfd);
5964 } else if ( pst->type==pst_lcaret ) {
5965 int i;
5966 fscanf( sfd, " %d", &pst->u.lcaret.cnt );
5967 pst->u.lcaret.carets = malloc(pst->u.lcaret.cnt*sizeof(int16));
5968 for ( i=0; i<pst->u.lcaret.cnt; ++i )
5969 fscanf( sfd, " %hd", &pst->u.lcaret.carets[i]);
5970 geteol(sfd,tok);
5971 } else {
5972 geteol(sfd,tok);
5973 pst->u.lig.components = copy(tok); /* it's in the same place for all formats */
5974 if ( isliga ) {
5975 pst->u.lig.lig = sc;
5976 if ( old )
5977 last = (PST *) LigaCreateFromOldStyleMultiple((PST1 *) pst);
5978 }
5979 }
5980 #ifdef FONTFORGE_CONFIG_CVT_OLD_MAC_FEATURES
5981 if ( old )
5982 CvtOldMacFeature((PST1 *) pst);
5983 #endif
5984 } else if ( strmatch(tok,"Colour:")==0 ) {
5985 uint32 temp;
5986 gethex(sfd,&temp);
5987 sc->color = temp;
5988 } else if ( strmatch(tok,"Comment:")==0 ) {
5989 sc->comment = SFDReadUTF7Str(sfd);
5990 } else if ( strmatch(tok,"Decomposition:")==0 ) {
5991 char* decomp = SFDReadUTF7Str(sfd);
5992 sc->user_decomp = utf82u_copy(decomp);
5993 free(decomp);
5994 } else if ( strmatch(tok,"TileMargin:")==0 ) {
5995 getreal(sfd,&sc->tile_margin);
5996 } else if ( strmatch(tok,"TileBounds:")==0 ) {
5997 getreal(sfd,&sc->tile_bounds.minx);
5998 getreal(sfd,&sc->tile_bounds.miny);
5999 getreal(sfd,&sc->tile_bounds.maxx);
6000 getreal(sfd,&sc->tile_bounds.maxy);
6001 } else if ( strmatch(tok,"EndChar")==0 ) {
6002 if ( sc->orig_pos<sf->glyphcnt )
6003 sf->glyphs[sc->orig_pos] = sc;
6004 /* Recalculating hint active zones may be needed for old .sfd files. */
6005 /* Do this when we have finished with other glyph components, */
6006 /* so that splines are already available */
6007 if ( sf->sfd_version<2 )
6008 SCGuessHintInstancesList( sc,ly_fore,sc->hstem,sc->vstem,sc->dstem,false,false );
6009 else if ( had_old_dstems && sc->layers[ly_fore].splines != NULL )
6010 SCGuessHintInstancesList( sc,ly_fore,NULL,NULL,sc->dstem,false,true );
6011 if ( sc->layers[ly_fore].order2 )
6012 SCDefaultInterpolation(sc);
6013 return( sc );
6014 } else {
6015 geteol(sfd,tok);
6016 }
6017 }
6018 }
6019
SFDGetBitmapProps(FILE * sfd,BDFFont * bdf,char * tok)6020 static int SFDGetBitmapProps(FILE *sfd,BDFFont *bdf,char *tok) {
6021 int pcnt;
6022 int i;
6023
6024 if ( getint(sfd,&pcnt)!=1 || pcnt<=0 )
6025 return( 0 );
6026 bdf->prop_cnt = pcnt;
6027 bdf->props = malloc(pcnt*sizeof(BDFProperties));
6028 for ( i=0; i<pcnt; ++i ) {
6029 if ( getname(sfd,tok)!=1 )
6030 break;
6031 if ( strcmp(tok,"BDFEndProperties")==0 )
6032 break;
6033 bdf->props[i].name = copy(tok);
6034 getint(sfd,&bdf->props[i].type);
6035 switch ( bdf->props[i].type&~prt_property ) {
6036 case prt_int: case prt_uint:
6037 getint(sfd,&bdf->props[i].u.val);
6038 break;
6039 case prt_string: case prt_atom:
6040 geteol(sfd,tok);
6041 if ( tok[strlen(tok)-1]=='"' ) tok[strlen(tok)-1] = '\0';
6042 bdf->props[i].u.str = copy(tok[0]=='"'?tok+1:tok);
6043 break;
6044 default:
6045 break;
6046 }
6047 }
6048 bdf->prop_cnt = i;
6049 return( 1 );
6050 }
6051
SFDGetBitmapChar(FILE * sfd,BDFFont * bdf)6052 static int SFDGetBitmapChar(FILE *sfd,BDFFont *bdf) {
6053 BDFChar *bfc;
6054 struct enc85 dec;
6055 int i, enc, orig;
6056 int width,xmax,xmin,ymax,ymin, vwidth=-1;
6057 EncMap *map;
6058 int ch;
6059
6060 map = bdf->sf->map;
6061
6062 if ( getint(sfd,&orig)!=1 || orig<0 )
6063 return( 0 );
6064 if ( getint(sfd,&enc)!=1 )
6065 return( 0 );
6066 if ( getint(sfd,&width)!=1 )
6067 return( 0 );
6068 if ( getint(sfd,&xmin)!=1 )
6069 return( 0 );
6070 if ( getint(sfd,&xmax)!=1 )
6071 return( 0 );
6072 if ( getint(sfd,&ymin)!=1 )
6073 return( 0 );
6074 while ( (ch=nlgetc(sfd))==' ');
6075 ungetc(ch,sfd);
6076 if ( ch=='\n' || ch=='\r' || getint(sfd,&ymax)!=1 ) {
6077 /* Old style format, no orig_pos given, shift everything by 1 */
6078 ymax = ymin;
6079 ymin = xmax;
6080 xmax = xmin;
6081 xmin = width;
6082 width = enc;
6083 enc = orig;
6084 orig = map->map[enc];
6085 } else {
6086 while ( (ch=nlgetc(sfd))==' ');
6087 ungetc(ch,sfd);
6088 if ( ch!='\n' && ch!='\r' )
6089 getint(sfd,&vwidth);
6090 }
6091 if ( enc<0 ||xmax<xmin || ymax<ymin )
6092 return( 0 );
6093
6094 bfc = chunkalloc(sizeof(BDFChar));
6095 if (bfc == NULL)
6096 return 0;
6097
6098 if ( orig==-1 ) {
6099 bfc->sc = SFMakeChar(bdf->sf,map,enc);
6100 orig = bfc->sc->orig_pos;
6101 }
6102
6103 bfc->orig_pos = orig;
6104 bfc->width = width;
6105 bfc->ymax = ymax; bfc->ymin = ymin;
6106 bfc->xmax = xmax; bfc->xmin = xmin;
6107 bdf->glyphs[orig] = bfc;
6108 bfc->sc = bdf->sf->glyphs[orig];
6109 bfc->vwidth = vwidth!=-1 ? vwidth :
6110 rint(bfc->sc->vwidth*bdf->pixelsize / (real) (bdf->sf->ascent+bdf->sf->descent));
6111 if ( bdf->clut==NULL ) {
6112 bfc->bytes_per_line = (bfc->xmax-bfc->xmin)/8 +1;
6113 bfc->depth = 1;
6114 } else {
6115 bfc->bytes_per_line = bfc->xmax-bfc->xmin +1;
6116 bfc->byte_data = true;
6117 bfc->depth = bdf->clut->clut_len==4 ? 2 : bdf->clut->clut_len==16 ? 4 : 8;
6118 }
6119 bfc->bitmap = calloc((bfc->ymax-bfc->ymin+1)*bfc->bytes_per_line,sizeof(uint8));
6120
6121 memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
6122 dec.sfd = sfd;
6123 for ( i=0; i<=bfc->ymax-bfc->ymin; ++i ) {
6124 uint8 *pt = (uint8 *) (bfc->bitmap + i*bfc->bytes_per_line);
6125 uint8 *end = (uint8 *) (bfc->bitmap + (i+1)*bfc->bytes_per_line);
6126 while ( pt<end ) {
6127 *pt++ = Dec85(&dec);
6128 }
6129 }
6130 if ( bfc->sc==NULL ) {
6131 bdf->glyphs[bfc->orig_pos] = NULL;
6132 BDFCharFree(bfc);
6133 }
6134 /* This fixes a bug: We didn't set "widthset" on splinechars when reading in */
6135 /* winfonts. We should set it now on any bitmaps worth outputting to make up*/
6136 /* for that. Eventually we should have good sfd files and can remove this */
6137 else if ( bfc->sc->width!=bdf->sf->ascent + bdf->sf->descent )
6138 bfc->sc->widthset = true;
6139 return( 1 );
6140 }
6141
SFDGetBitmapReference(FILE * sfd,BDFFont * bdf)6142 static int SFDGetBitmapReference(FILE *sfd,BDFFont *bdf) {
6143 BDFChar *bc;
6144 BDFRefChar *ref, *head;
6145 int gid, rgid, xoff, yoff;
6146 char ch;
6147
6148 /* 'BDFRefChar:' elements should not occur in the file before the corresponding */
6149 /* 'BDFChar:'. However it is possible that the glyphs they refer to are not yet */
6150 /* available. So we will find them later */
6151 if ( getint(sfd,&gid)!=1 || gid<=0 || gid >= bdf->glyphcnt || ( bc = bdf->glyphs[gid] ) == NULL )
6152 return( 0 );
6153 if ( getint(sfd,&rgid)!=1 || rgid<0 )
6154 return( 0 );
6155 if ( getint(sfd,&xoff)!=1 )
6156 return( 0 );
6157 if ( getint(sfd,&yoff)!=1 )
6158 return( 0 );
6159 while ( isspace( ch=nlgetc( sfd )) && ch!='\r' && ch!='\n' );
6160
6161 ref = calloc( 1,sizeof( BDFRefChar ));
6162 ref->gid = rgid; ref->xoff = xoff, ref->yoff = yoff;
6163 if ( ch == 'S' ) ref->selected = true;
6164 for ( head = bc->refs; head != NULL && head->next!=NULL; head = head->next );
6165 if ( head == NULL ) bc->refs = ref;
6166 else head->next = ref;
6167 return( 1 );
6168 }
6169
SFDFixupBitmapRefs(BDFFont * bdf)6170 static void SFDFixupBitmapRefs( BDFFont *bdf ) {
6171 BDFChar *bc, *rbc;
6172 BDFRefChar *head, *next, *prev;
6173 int i;
6174
6175 for ( i=0; i<bdf->glyphcnt; i++ ) if (( bc = bdf->glyphs[i] ) != NULL ) {
6176 prev = NULL;
6177 for ( head = bc->refs; head != NULL; head = next ) {
6178 next = head->next;
6179 if (( rbc = bdf->glyphs[head->gid] ) != NULL ) {
6180 head->bdfc = rbc;
6181 BCMakeDependent( bc,rbc );
6182 prev = head;
6183 } else {
6184 LogError(_("Glyph %d in bitmap strike %d pixels refers to a missing glyph (%d)"),
6185 bc->orig_pos, bdf->pixelsize, head->gid );
6186 if ( prev == NULL ) bc->refs = next;
6187 else prev->next = next;
6188 }
6189 }
6190 }
6191
6192 }
6193
SFDGetBitmapFont(FILE * sfd,SplineFont * sf,int fromdir,char * dirname)6194 static int SFDGetBitmapFont(FILE *sfd,SplineFont *sf,int fromdir,char *dirname) {
6195 BDFFont *bdf, *prev;
6196 char tok[2000];
6197 int pixelsize, ascent, descent, depth=1;
6198 int ch, enccount;
6199
6200 if ( getint(sfd,&pixelsize)!=1 || pixelsize<=0 )
6201 return( 0 );
6202 if ( getint(sfd,&enccount)!=1 || enccount<0 )
6203 return( 0 );
6204 if ( getint(sfd,&ascent)!=1 || ascent<0 )
6205 return( 0 );
6206 if ( getint(sfd,&descent)!=1 || descent<0 )
6207 return( 0 );
6208 if ( getint(sfd,&depth)!=1 )
6209 depth = 1; /* old sfds don't have a depth here */
6210 else if ( depth!=1 && depth!=2 && depth!=4 && depth!=8 )
6211 return( 0 );
6212 while ( (ch = nlgetc(sfd))==' ' );
6213 ungetc(ch,sfd); /* old sfds don't have a foundry */
6214
6215 bdf = calloc(1,sizeof(BDFFont));
6216 if (bdf == NULL)
6217 return 0;
6218
6219 if ( ch!='\n' && ch!='\r' ) {
6220 getname(sfd,tok);
6221 bdf->foundry = copy(tok);
6222 }
6223 bdf->pixelsize = pixelsize;
6224 bdf->ascent = ascent;
6225 bdf->descent = descent;
6226 if ( depth!=1 )
6227 BDFClut(bdf,(1<<(depth/2)));
6228
6229 if ( sf->bitmaps==NULL )
6230 sf->bitmaps = bdf;
6231 else {
6232 for ( prev=sf->bitmaps; prev->next!=NULL; prev=prev->next );
6233 prev->next = bdf;
6234 }
6235 bdf->sf = sf;
6236 bdf->glyphcnt = bdf->glyphmax = sf->glyphcnt;
6237 bdf->glyphs = calloc(bdf->glyphcnt,sizeof(BDFChar *));
6238
6239 while ( getname(sfd,tok)==1 ) {
6240 if ( strcmp(tok,"BDFStartProperties:")==0 )
6241 SFDGetBitmapProps(sfd,bdf,tok);
6242 else if ( strcmp(tok,"BDFEndProperties")==0 )
6243 /* Do Nothing */;
6244 else if ( strcmp(tok,"Resolution:")==0 )
6245 getint(sfd,&bdf->res);
6246 else if ( strcmp(tok,"BDFChar:")==0 )
6247 SFDGetBitmapChar(sfd,bdf);
6248 else if ( strcmp(tok,"BDFRefChar:")==0 )
6249 SFDGetBitmapReference(sfd,bdf);
6250 else if ( strcmp(tok,"EndBitmapFont")==0 )
6251 break;
6252 }
6253 if ( fromdir ) {
6254 DIR *dir;
6255 struct dirent *ent;
6256 char *name;
6257
6258 dir = opendir(dirname);
6259 if ( dir==NULL )
6260 return( 0 );
6261 name = malloc(strlen(dirname)+NAME_MAX+3);
6262
6263 while ( (ent=readdir(dir))!=NULL ) {
6264 char *pt = strrchr(ent->d_name,EXT_CHAR);
6265 if ( pt==NULL )
6266 /* Nothing interesting */;
6267 else if ( strcmp(pt,BITMAP_EXT)==0 ) {
6268 FILE *gsfd;
6269 sprintf(name,"%s/%s", dirname, ent->d_name);
6270 gsfd = fopen(name,"r");
6271 if ( gsfd!=NULL ) {
6272 if ( getname(gsfd,tok) && strcmp(tok,"BDFChar:")==0)
6273 SFDGetBitmapChar(gsfd,bdf);
6274 fclose(gsfd);
6275 ff_progress_next();
6276 }
6277 }
6278 }
6279 free(name);
6280 closedir(dir);
6281 }
6282 SFDFixupBitmapRefs( bdf );
6283 return( 1 );
6284 }
6285
SFDFixupRef(SplineChar * sc,RefChar * ref,int layer)6286 static void SFDFixupRef(SplineChar *sc,RefChar *ref,int layer) {
6287 RefChar *rf;
6288 int ly;
6289
6290 if ( sc->parent->multilayer ) {
6291 for ( ly=ly_fore; ly<ref->sc->layer_cnt; ++ly ) {
6292 for ( rf = ref->sc->layers[ly].refs; rf!=NULL; rf=rf->next ) {
6293 if ( rf->sc==sc ) { /* Huh? */
6294 ref->sc->layers[ly].refs = NULL;
6295 break;
6296 }
6297 if ( rf->layers[0].splines==NULL )
6298 SFDFixupRef(ref->sc,rf,layer);
6299 }
6300 }
6301 } else {
6302 for ( rf = ref->sc->layers[layer].refs; rf!=NULL; rf=rf->next ) {
6303 if ( rf->sc==sc ) { /* Huh? */
6304 ref->sc->layers[layer].refs = NULL;
6305 break;
6306 }
6307 if ( rf->layers[0].splines==NULL )
6308 SFDFixupRef(ref->sc,rf,layer);
6309 }
6310 }
6311 SCReinstanciateRefChar(sc,ref,layer);
6312 SCMakeDependent(sc,ref->sc);
6313 }
6314
6315 /* Look for character duplicates, such as might be generated by having the same */
6316 /* glyph at two encoding slots */
6317 /* This is an obsolete convention, supported now only in sfd files */
6318 /* I think it is ok if something depends on this character, because the */
6319 /* code that handles references will automatically unwrap it down to be base */
SCDuplicate(SplineChar * sc)6320 static SplineChar *SCDuplicate(SplineChar *sc) {
6321 SplineChar *matched = sc;
6322
6323 if ( sc==NULL || sc->parent==NULL || sc->parent->cidmaster!=NULL )
6324 return( sc ); /* Can't do this in CID keyed fonts */
6325
6326 if ( sc->layer_cnt!=2 )
6327 return( sc );
6328
6329 while ( sc->layers[ly_fore].refs!=NULL &&
6330 sc->layers[ly_fore].refs->sc!=NULL && /* Can happen if we are called during font loading before references are fixed up */
6331 sc->layers[ly_fore].refs->next==NULL &&
6332 sc->layers[ly_fore].refs->transform[0]==1 && sc->layers[ly_fore].refs->transform[1]==0 &&
6333 sc->layers[ly_fore].refs->transform[2]==0 && sc->layers[ly_fore].refs->transform[3]==1 &&
6334 sc->layers[ly_fore].refs->transform[4]==0 && sc->layers[ly_fore].refs->transform[5]==0 ) {
6335 char *basename = sc->layers[ly_fore].refs->sc->name;
6336 if ( strcmp(sc->name,basename)!=0 )
6337 break;
6338 matched = sc->layers[ly_fore].refs->sc;
6339 sc = sc->layers[ly_fore].refs->sc;
6340 }
6341 return( matched );
6342 }
6343
SFDFixupUndoRefsUndoList(SplineFont * sf,Undoes * undo)6344 static void SFDFixupUndoRefsUndoList(SplineFont *sf,Undoes *undo) {
6345 for( ; undo; undo = undo->next ) {
6346 if( undo->undotype == ut_state && undo->u.state.refs ) {
6347 RefChar *ref=NULL;
6348 for ( ref=undo->u.state.refs; ref!=NULL; ref=ref->next ) {
6349
6350 ref->sc = sf->glyphs[ ref->orig_pos ];
6351 }
6352 }
6353 }
6354 }
6355
SFDFixupUndoRefs(SplineFont * sf)6356 static void SFDFixupUndoRefs(SplineFont *sf) {
6357 int i=0;
6358 Undoes *undo = 0;
6359
6360 for ( i=0; i<sf->glyphcnt; ++i ) {
6361 if ( sf->glyphs[i]!=NULL ) {
6362 SplineChar *sc = sf->glyphs[i];
6363 int layer = 0;
6364 for ( layer=0; layer<sc->layer_cnt; ++layer ) {
6365 if( sc->layers[layer].undoes ) {
6366 undo = sc->layers[layer].undoes;
6367 SFDFixupUndoRefsUndoList( sf, undo );
6368 }
6369 if( sc->layers[layer].redoes ) {
6370 undo = sc->layers[layer].redoes;
6371 SFDFixupUndoRefsUndoList( sf, undo );
6372 }
6373 }
6374 }
6375 }
6376
6377
6378 }
6379
6380
SFDFixupRefs(SplineFont * sf)6381 void SFDFixupRefs(SplineFont *sf) {
6382 int i, isv;
6383 RefChar *refs, *rnext, *rprev;
6384 /*int isautorecovery = sf->changed;*/
6385 KernPair *kp, *prev, *next;
6386 EncMap *map = sf->map;
6387 int layer;
6388 int k,l;
6389 SplineFont *cidmaster = sf, *ksf;
6390
6391 k = 1;
6392 if ( sf->subfontcnt!=0 )
6393 sf = sf->subfonts[0];
6394
6395 ff_progress_change_line2(_("Interpreting Glyphs"));
6396 for (;;) {
6397 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
6398 SplineChar *sc = sf->glyphs[i];
6399 /* A changed character is one that has just been recovered */
6400 /* unchanged characters will already have been fixed up */
6401 /* Er... maybe not. If the character being recovered is refered to */
6402 /* by another character then we need to fix up that other char too*/
6403 /*if ( isautorecovery && !sc->changed )*/
6404 /*continue;*/
6405 for ( layer = 0; layer<sc->layer_cnt; ++layer ) {
6406 rprev = NULL;
6407 for ( refs = sc->layers[layer].refs; refs!=NULL; refs=rnext ) {
6408 rnext = refs->next;
6409 if ( refs->encoded ) { /* Old sfd format */
6410 if ( refs->orig_pos<map->encmax && map->map[refs->orig_pos]!=-1 )
6411 refs->orig_pos = map->map[refs->orig_pos];
6412 else
6413 refs->orig_pos = sf->glyphcnt;
6414 refs->encoded = false;
6415 }
6416 if ( refs->orig_pos<sf->glyphcnt && refs->orig_pos>=0 )
6417 refs->sc = sf->glyphs[refs->orig_pos];
6418 if ( refs->sc!=NULL ) {
6419 refs->unicode_enc = refs->sc->unicodeenc;
6420 refs->adobe_enc = getAdobeEnc(refs->sc->name);
6421 rprev = refs;
6422 if ( refs->use_my_metrics ) {
6423 if ( sc->width != refs->sc->width ) {
6424 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"),
6425 sc->name, sc->width, refs->sc->name, refs->sc->width );
6426 sc->width = refs->sc->width;
6427 }
6428 }
6429 } else {
6430 RefCharFree(refs);
6431 if ( rprev!=NULL )
6432 rprev->next = rnext;
6433 else
6434 sc->layers[layer].refs = rnext;
6435 }
6436 }
6437 }
6438 /* In old sfd files we used a peculiar idiom to represent a multiply */
6439 /* encoded glyph. Fix it up now. Remove the fake glyph and adjust the*/
6440 /* map */
6441 /*if ( isautorecovery && !sc->changed )*/
6442 /*continue;*/
6443 for ( isv=0; isv<2; ++isv ) {
6444 for ( prev = NULL, kp=isv?sc->vkerns : sc->kerns; kp!=NULL; kp=next ) {
6445 int index = (intpt) (kp->sc);
6446
6447 next = kp->next;
6448 // be impotent if the reference is already to the correct location
6449 if ( !kp->kcid ) { /* It's encoded (old sfds), else orig */
6450 if ( index>=map->encmax || map->map[index]==-1 )
6451 index = sf->glyphcnt;
6452 else
6453 index = map->map[index];
6454 }
6455 kp->kcid = false;
6456 ksf = sf;
6457 if ( cidmaster!=sf ) {
6458 for ( l=0; l<cidmaster->subfontcnt; ++l ) {
6459 ksf = cidmaster->subfonts[l];
6460 if ( index<ksf->glyphcnt && ksf->glyphs[index]!=NULL )
6461 break;
6462 }
6463 }
6464 if ( index>=ksf->glyphcnt || ksf->glyphs[index]==NULL ) {
6465 IError( "Bad kerning information in glyph %s\n", sc->name );
6466 kp->sc = NULL;
6467 } else {
6468 kp->sc = ksf->glyphs[index];
6469 }
6470
6471 if ( kp->sc!=NULL )
6472 prev = kp;
6473 else{
6474 if ( prev!=NULL )
6475 prev->next = next;
6476 else if ( isv )
6477 sc->vkerns = next;
6478 else
6479 sc->kerns = next;
6480 chunkfree(kp,sizeof(KernPair));
6481 }
6482 }
6483 }
6484 if ( SCDuplicate(sc)!=sc ) {
6485 SplineChar *base = SCDuplicate(sc);
6486 int orig = sc->orig_pos, enc = sf->map->backmap[orig], uni = sc->unicodeenc;
6487 SplineCharFree(sc);
6488 sf->glyphs[i]=NULL;
6489 sf->map->backmap[orig] = -1;
6490 sf->map->map[enc] = base->orig_pos;
6491 AltUniAdd(base,uni);
6492 }
6493 }
6494 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
6495 SplineChar *sc = sf->glyphs[i];
6496 for ( layer=0; layer<sc->layer_cnt; ++layer ) {
6497 for ( refs = sf->glyphs[i]->layers[layer].refs; refs!=NULL; refs=refs->next ) {
6498 SFDFixupRef(sf->glyphs[i],refs,layer);
6499 }
6500 }
6501 ff_progress_next();
6502 }
6503 if ( sf->cidmaster==NULL )
6504 for ( i=sf->glyphcnt-1; i>=0 && sf->glyphs[i]==NULL; --i )
6505 sf->glyphcnt = i;
6506 if ( k>=cidmaster->subfontcnt )
6507 break;
6508 sf = cidmaster->subfonts[k++];
6509 }
6510 }
6511
6512 /* When we recover from an autosaved file we must be careful. If that file */
6513 /* contains a character that is refered to by another character then the */
6514 /* dependent list will contain a dead pointer without this routine. Similarly*/
6515 /* for kerning */
6516 /* We might have needed to do something for references except they've already */
6517 /* got a orig_pos field and passing through SFDFixupRefs will munch their*/
6518 /* SplineChar pointer */
SFRemoveDependencies(SplineFont * sf)6519 static void SFRemoveDependencies(SplineFont *sf) {
6520 int i;
6521 struct splinecharlist *dlist, *dnext;
6522 KernPair *kp;
6523
6524 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
6525 for ( dlist = sf->glyphs[i]->dependents; dlist!=NULL; dlist = dnext ) {
6526 dnext = dlist->next;
6527 chunkfree(dlist,sizeof(*dlist));
6528 }
6529 sf->glyphs[i]->dependents = NULL;
6530 for ( kp=sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
6531 kp->sc = (SplineChar *) (intpt) (kp->sc->orig_pos);
6532 kp->kcid = true; /* flag */
6533 }
6534 for ( kp=sf->glyphs[i]->vkerns; kp!=NULL; kp=kp->next ) {
6535 kp->sc = (SplineChar *) (intpt) (kp->sc->orig_pos);
6536 kp->kcid = true;
6537 }
6538 }
6539 }
6540
SFDGetPrivate(FILE * sfd,SplineFont * sf)6541 static void SFDGetPrivate(FILE *sfd,SplineFont *sf) {
6542 int i, cnt, len;
6543 char name[200];
6544 char *pt, *end;
6545
6546 sf->private = calloc(1,sizeof(struct psdict));
6547 getint(sfd,&cnt);
6548 sf->private->next = sf->private->cnt = cnt;
6549 sf->private->values = calloc(cnt,sizeof(char *));
6550 sf->private->keys = calloc(cnt,sizeof(char *));
6551 for ( i=0; i<cnt; ++i ) {
6552 getname(sfd,name);
6553 sf->private->keys[i] = copy(name);
6554 getint(sfd,&len);
6555 nlgetc(sfd); /* skip space */
6556 pt = sf->private->values[i] = malloc(len+1);
6557 for ( end = pt+len; pt<end; ++pt )
6558 *pt = nlgetc(sfd);
6559 *pt='\0';
6560 }
6561 }
6562
SFDGetSubrs(FILE * sfd)6563 static void SFDGetSubrs(FILE *sfd) {
6564 /* Obselete, parse it in case there are any old sfds */
6565 int i, cnt, tot, len;
6566 struct enc85 dec;
6567
6568 getint(sfd,&cnt);
6569 tot = 0;
6570 for ( i=0; i<cnt; ++i ) {
6571 getint(sfd,&len);
6572 tot += len;
6573 }
6574
6575 memset(&dec,'\0', sizeof(dec)); dec.pos = -1;
6576 dec.sfd = sfd;
6577 for ( i=0; i<tot; ++i )
6578 Dec85(&dec);
6579 }
6580
SFDGetLangName(FILE * sfd,struct ttflangname * old)6581 static struct ttflangname *SFDGetLangName(FILE *sfd,struct ttflangname *old) {
6582 struct ttflangname *cur = chunkalloc(sizeof(struct ttflangname)), *prev;
6583 int i;
6584
6585 getint(sfd,&cur->lang);
6586 for ( i=0; i<ttf_namemax; ++i )
6587 cur->names[i] = SFDReadUTF7Str(sfd);
6588 if ( old==NULL )
6589 return( cur );
6590 for ( prev = old; prev->next !=NULL; prev = prev->next );
6591 prev->next = cur;
6592 return( old );
6593 }
6594
SFDGetGasp(FILE * sfd,SplineFont * sf)6595 static void SFDGetGasp(FILE *sfd,SplineFont *sf) {
6596 int i;
6597
6598 getsint(sfd,(int16 *) &sf->gasp_cnt);
6599 sf->gasp = malloc(sf->gasp_cnt*sizeof(struct gasp));
6600 for ( i=0; i<sf->gasp_cnt; ++i ) {
6601 getsint(sfd,(int16 *) &sf->gasp[i].ppem);
6602 getsint(sfd,(int16 *) &sf->gasp[i].flags);
6603 }
6604 getsint(sfd,(int16 *) &sf->gasp_version);
6605 }
6606
SFDGetDesignSize(FILE * sfd,SplineFont * sf)6607 static void SFDGetDesignSize(FILE *sfd,SplineFont *sf) {
6608 int ch;
6609 struct otfname *cur;
6610
6611 getsint(sfd,(int16 *) &sf->design_size);
6612 while ( (ch=nlgetc(sfd))==' ' );
6613 ungetc(ch,sfd);
6614 if ( isdigit(ch)) {
6615 getsint(sfd,(int16 *) &sf->design_range_bottom);
6616 while ( (ch=nlgetc(sfd))==' ' );
6617 if ( ch!='-' )
6618 ungetc(ch,sfd);
6619 getsint(sfd,(int16 *) &sf->design_range_top);
6620 getsint(sfd,(int16 *) &sf->fontstyle_id);
6621 for (;;) {
6622 while ( (ch=nlgetc(sfd))==' ' );
6623 ungetc(ch,sfd);
6624 if ( !isdigit(ch))
6625 break;
6626 cur = chunkalloc(sizeof(struct otfname));
6627 cur->next = sf->fontstyle_name;
6628 sf->fontstyle_name = cur;
6629 getsint(sfd,(int16 *) &cur->lang);
6630 cur->name = SFDReadUTF7Str(sfd);
6631 }
6632 }
6633 }
6634
SFDGetOtfFeatName(FILE * sfd,SplineFont * sf)6635 static void SFDGetOtfFeatName(FILE *sfd,SplineFont *sf) {
6636 int ch;
6637 struct otfname *cur;
6638 struct otffeatname *fn;
6639
6640 fn = chunkalloc(sizeof(struct otffeatname));
6641 fn->tag = gettag(sfd);
6642 for (;;) {
6643 while ( (ch=nlgetc(sfd))==' ' );
6644 ungetc(ch,sfd);
6645 if ( !isdigit(ch))
6646 break;
6647 cur = chunkalloc(sizeof(struct otfname));
6648 cur->next = fn->names;
6649 fn->names = cur;
6650 getsint(sfd,(int16 *) &cur->lang);
6651 cur->name = SFDReadUTF7Str(sfd);
6652 }
6653 fn->next = sf->feat_names;
6654 sf->feat_names = fn;
6655 }
6656
SFDGetEncoding(FILE * sfd,char * tok)6657 static Encoding *SFDGetEncoding(FILE *sfd, char *tok) {
6658 Encoding *enc = NULL;
6659 int encname;
6660
6661 if ( getint(sfd,&encname) ) {
6662 if ( encname<(int)(sizeof(charset_names)/sizeof(charset_names[0])-1) )
6663 enc = FindOrMakeEncoding(charset_names[encname]);
6664 } else {
6665 geteol(sfd,tok);
6666 enc = FindOrMakeEncoding(tok);
6667 }
6668 if ( enc==NULL )
6669 enc = &custom;
6670 return( enc );
6671 }
6672
SFDGetUniInterp(FILE * sfd,char * tok,SplineFont * sf)6673 static enum uni_interp SFDGetUniInterp(FILE *sfd, char *tok, SplineFont *sf) {
6674 int uniinterp = ui_none;
6675 int i;
6676
6677 geteol(sfd,tok);
6678 for ( i=0; unicode_interp_names[i]!=NULL; ++i )
6679 if ( strcmp(tok,unicode_interp_names[i])==0 ) {
6680 uniinterp = i;
6681 break;
6682 }
6683 /* These values are now handled by namelists */
6684 if ( uniinterp == ui_adobe ) {
6685 sf->for_new_glyphs = NameListByName("AGL with PUA");
6686 uniinterp = ui_none;
6687 } else if ( uniinterp == ui_greek ) {
6688 sf->for_new_glyphs = NameListByName("Greek small caps");
6689 uniinterp = ui_none;
6690 } else if ( uniinterp == ui_ams ) {
6691 sf->for_new_glyphs = NameListByName("AMS Names");
6692 uniinterp = ui_none;
6693 }
6694
6695 return( uniinterp );
6696 }
6697
SFDGetNameList(FILE * sfd,char * tok,SplineFont * sf)6698 static void SFDGetNameList(FILE *sfd, char *tok, SplineFont *sf) {
6699 NameList *nl;
6700
6701 geteol(sfd,tok);
6702 nl = NameListByName(tok);
6703 if ( nl==NULL )
6704 LogError(_("Failed to find NameList: %s"), tok);
6705 else
6706 sf->for_new_glyphs = nl;
6707 }
6708
6709
SFD_ParseNestedLookup(FILE * sfd,SplineFont * sf,int old)6710 static OTLookup *SFD_ParseNestedLookup(FILE *sfd, SplineFont *sf, int old) {
6711 uint32 tag;
6712 int ch, isgpos;
6713 OTLookup *otl;
6714 char *name;
6715
6716 while ( (ch=nlgetc(sfd))==' ' );
6717 if ( ch=='~' )
6718 return( NULL );
6719 else if ( old ) {
6720 if ( ch!='\'' )
6721 return( NULL );
6722
6723 ungetc(ch,sfd);
6724 tag = gettag(sfd);
6725 return( (OTLookup *) (intpt) tag );
6726 } else {
6727 ungetc(ch,sfd);
6728 name = SFDReadUTF7Str(sfd);
6729 if ( name==NULL )
6730 return( NULL );
6731 for ( isgpos=0; isgpos<2; ++isgpos ) {
6732 for ( otl=isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl=otl->next ) {
6733 if ( strcmp(name,otl->lookup_name )==0 )
6734 goto break2;
6735 }
6736 }
6737 break2:
6738 free(name);
6739 return( otl );
6740 }
6741 }
6742
SFDParseChainContext(FILE * sfd,SplineFont * sf,FPST * fpst,char * tok,int old)6743 static void SFDParseChainContext(FILE *sfd,SplineFont *sf,FPST *fpst, char *tok, int old) {
6744 int ch, i, j, k, temp;
6745 SplineFont *sli_sf = sf->cidmaster ? sf->cidmaster : sf;
6746
6747 fpst->type = strnmatch(tok,"ContextPos",10)==0 ? pst_contextpos :
6748 strnmatch(tok,"ContextSub",10)==0 ? pst_contextsub :
6749 strnmatch(tok,"ChainPos",8)==0 ? pst_chainpos :
6750 strnmatch(tok,"ChainSub",8)==0 ? pst_chainsub : pst_reversesub;
6751 getname(sfd,tok);
6752 fpst->format = strmatch(tok,"glyph")==0 ? pst_glyphs :
6753 strmatch(tok,"class")==0 ? pst_class :
6754 strmatch(tok,"coverage")==0 ? pst_coverage : pst_reversecoverage;
6755 if ( old ) {
6756 fscanf(sfd, "%hu %hu", &((FPST1 *) fpst)->flags, &((FPST1 *) fpst)->script_lang_index );
6757 if ( ((FPST1 *) fpst)->script_lang_index>=((SplineFont1 *) sli_sf)->sli_cnt && ((FPST1 *) fpst)->script_lang_index!=SLI_NESTED ) {
6758 static int complained=false;
6759 if ( ((SplineFont1 *) sli_sf)->sli_cnt==0 )
6760 IError("'%c%c%c%c' has a script index out of bounds: %d\nYou MUST fix this manually",
6761 (((FPST1 *) fpst)->tag>>24), (((FPST1 *) fpst)->tag>>16)&0xff, (((FPST1 *) fpst)->tag>>8)&0xff, ((FPST1 *) fpst)->tag&0xff,
6762 ((FPST1 *) fpst)->script_lang_index );
6763 else if ( !complained )
6764 IError("'%c%c%c%c' has a script index out of bounds: %d",
6765 (((FPST1 *) fpst)->tag>>24), (((FPST1 *) fpst)->tag>>16)&0xff, (((FPST1 *) fpst)->tag>>8)&0xff, ((FPST1 *) fpst)->tag&0xff,
6766 ((FPST1 *) fpst)->script_lang_index );
6767 else
6768 IError("'%c%c%c%c' has a script index out of bounds: %d\n",
6769 (((FPST1 *) fpst)->tag>>24), (((FPST1 *) fpst)->tag>>16)&0xff, (((FPST1 *) fpst)->tag>>8)&0xff, ((FPST1 *) fpst)->tag&0xff,
6770 ((FPST1 *) fpst)->script_lang_index );
6771 if ( ((SplineFont1 *) sli_sf)->sli_cnt!=0 )
6772 ((FPST1 *) fpst)->script_lang_index = ((SplineFont1 *) sli_sf)->sli_cnt-1;
6773 complained = true;
6774 }
6775 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
6776 if ( ch=='\'' ) {
6777 ungetc(ch,sfd);
6778 ((FPST1 *) fpst)->tag = gettag(sfd);
6779 } else
6780 ungetc(ch,sfd);
6781 } else {
6782 fpst->subtable = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
6783 if ( !fpst->subtable )
6784 LogError(_("Missing Subtable definition found in chained context"));
6785 else
6786 fpst->subtable->fpst = fpst;
6787 }
6788 fscanf(sfd, "%hu %hu %hu %hu", &fpst->nccnt, &fpst->bccnt, &fpst->fccnt, &fpst->rule_cnt );
6789 if ( fpst->nccnt!=0 || fpst->bccnt!=0 || fpst->fccnt!=0 ) {
6790 fpst->nclass = malloc(fpst->nccnt*sizeof(char *));
6791 fpst->nclassnames = calloc(fpst->nccnt,sizeof(char *));
6792 if ( fpst->nccnt!=0 ) fpst->nclass[0] = NULL;
6793 if ( fpst->bccnt!=0 || fpst->fccnt!=0 ) {
6794 fpst->bclass = malloc(fpst->bccnt*sizeof(char *));
6795 fpst->bclassnames = calloc(fpst->bccnt,sizeof(char *));
6796 if (fpst->bccnt!=0 ) fpst->bclass[0] = NULL;
6797 fpst->fclass = malloc(fpst->fccnt*sizeof(char *));
6798 fpst->fclassnames = calloc(fpst->fccnt,sizeof(char *));
6799 if (fpst->fccnt!=0 ) fpst->fclass[0] = NULL;
6800 }
6801 }
6802
6803 for ( j=0; j<3; ++j ) {
6804 for ( i=1; i<(&fpst->nccnt)[j]; ++i ) {
6805 getname(sfd,tok);
6806 if ( i==1 && j==0 && strcmp(tok,"Class0:")==0 )
6807 i=0;
6808 getint(sfd,&temp);
6809 (&fpst->nclass)[j][i] = malloc(temp+1); (&fpst->nclass)[j][i][temp] = '\0';
6810 nlgetc(sfd); /* skip space */
6811 fread((&fpst->nclass)[j][i],1,temp,sfd);
6812 }
6813 }
6814
6815 fpst->rules = calloc(fpst->rule_cnt,sizeof(struct fpst_rule));
6816 for ( i=0; i<fpst->rule_cnt; ++i ) {
6817 switch ( fpst->format ) {
6818 case pst_glyphs:
6819 for ( j=0; j<3; ++j ) {
6820 getname(sfd,tok);
6821 getint(sfd,&temp);
6822 (&fpst->rules[i].u.glyph.names)[j] = malloc(temp+1);
6823 (&fpst->rules[i].u.glyph.names)[j][temp] = '\0';
6824 nlgetc(sfd); /* skip space */
6825 fread((&fpst->rules[i].u.glyph.names)[j],1,temp,sfd);
6826 }
6827 break;
6828 case pst_class:
6829 fscanf( sfd, "%d %d %d", &fpst->rules[i].u.class.ncnt, &fpst->rules[i].u.class.bcnt, &fpst->rules[i].u.class.fcnt );
6830 for ( j=0; j<3; ++j ) {
6831 getname(sfd,tok);
6832 (&fpst->rules[i].u.class.nclasses)[j] = malloc((&fpst->rules[i].u.class.ncnt)[j]*sizeof(uint16));
6833 for ( k=0; k<(&fpst->rules[i].u.class.ncnt)[j]; ++k ) {
6834 getusint(sfd,&(&fpst->rules[i].u.class.nclasses)[j][k]);
6835 }
6836 }
6837 break;
6838 case pst_coverage:
6839 case pst_reversecoverage:
6840 fscanf( sfd, "%d %d %d", &fpst->rules[i].u.coverage.ncnt, &fpst->rules[i].u.coverage.bcnt, &fpst->rules[i].u.coverage.fcnt );
6841 for ( j=0; j<3; ++j ) {
6842 (&fpst->rules[i].u.coverage.ncovers)[j] = malloc((&fpst->rules[i].u.coverage.ncnt)[j]*sizeof(char *));
6843 for ( k=0; k<(&fpst->rules[i].u.coverage.ncnt)[j]; ++k ) {
6844 getname(sfd,tok);
6845 getint(sfd,&temp);
6846 (&fpst->rules[i].u.coverage.ncovers)[j][k] = malloc(temp+1);
6847 (&fpst->rules[i].u.coverage.ncovers)[j][k][temp] = '\0';
6848 nlgetc(sfd); /* skip space */
6849 fread((&fpst->rules[i].u.coverage.ncovers)[j][k],1,temp,sfd);
6850 }
6851 }
6852 break;
6853 default:
6854 break;
6855 }
6856 switch ( fpst->format ) {
6857 case pst_glyphs:
6858 case pst_class:
6859 case pst_coverage:
6860 getint(sfd,&fpst->rules[i].lookup_cnt);
6861 fpst->rules[i].lookups = malloc(fpst->rules[i].lookup_cnt*sizeof(struct seqlookup));
6862 for ( j=k=0; j<fpst->rules[i].lookup_cnt; ++j ) {
6863 getname(sfd,tok);
6864 getint(sfd,&fpst->rules[i].lookups[j].seq);
6865 fpst->rules[i].lookups[k].lookup = SFD_ParseNestedLookup(sfd,sf,old);
6866 if ( fpst->rules[i].lookups[k].lookup!=NULL )
6867 ++k;
6868 }
6869 fpst->rules[i].lookup_cnt = k;
6870 break;
6871 case pst_reversecoverage:
6872 getname(sfd,tok);
6873 getint(sfd,&temp);
6874 fpst->rules[i].u.rcoverage.replacements = malloc(temp+1);
6875 fpst->rules[i].u.rcoverage.replacements[temp] = '\0';
6876 nlgetc(sfd); /* skip space */
6877 fread(fpst->rules[i].u.rcoverage.replacements,1,temp,sfd);
6878 break;
6879 default:
6880 break;
6881 }
6882 }
6883 getname(sfd,tok); /* EndFPST, or one of the ClassName tokens (in newer sfds) */
6884 while ( strcmp(tok,"ClassNames:")==0 || strcmp(tok,"BClassNames:")==0 ||
6885 strcmp(tok,"FClassNames:")==0 ) {
6886 int which = strcmp(tok,"ClassNames:")==0 ? 0 :
6887 strcmp(tok,"BClassNames:")==0 ? 1 : 2;
6888 int cnt = (&fpst->nccnt)[which];
6889 char **classnames = (&fpst->nclassnames)[which];
6890 int i;
6891
6892 for ( i=0; i<cnt; ++i )
6893 classnames[i] = SFDReadUTF7Str(sfd);
6894 getname(sfd,tok); /* EndFPST, or one of the ClassName tokens (in newer sfds) */
6895 }
6896
6897 }
6898
SFDParseStateMachine(FILE * sfd,SplineFont * sf,ASM * sm,char * tok,int old)6899 static void SFDParseStateMachine(FILE *sfd,SplineFont *sf,ASM *sm, char *tok,int old) {
6900 int i, temp;
6901
6902 sm->type = strnmatch(tok,"MacIndic",8)==0 ? asm_indic :
6903 strnmatch(tok,"MacContext",10)==0 ? asm_context :
6904 strnmatch(tok,"MacLigature",11)==0 ? asm_lig :
6905 strnmatch(tok,"MacSimple",9)==0 ? asm_simple :
6906 strnmatch(tok,"MacKern",7)==0 ? asm_kern : asm_insert;
6907 if ( old ) {
6908 getusint(sfd,&((ASM1 *) sm)->feature);
6909 nlgetc(sfd); /* Skip comma */
6910 getusint(sfd,&((ASM1 *) sm)->setting);
6911 } else {
6912 sm->subtable = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
6913 sm->subtable->sm = sm;
6914 }
6915 getusint(sfd,&sm->flags);
6916 getusint(sfd,&sm->class_cnt);
6917 getusint(sfd,&sm->state_cnt);
6918
6919 sm->classes = malloc(sm->class_cnt*sizeof(char *));
6920 sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
6921 for ( i=4; i<sm->class_cnt; ++i ) {
6922 getname(sfd,tok);
6923 getint(sfd,&temp);
6924 sm->classes[i] = malloc(temp+1); sm->classes[i][temp] = '\0';
6925 nlgetc(sfd); /* skip space */
6926 fread(sm->classes[i],1,temp,sfd);
6927 }
6928
6929 sm->state = malloc(sm->class_cnt*sm->state_cnt*sizeof(struct asm_state));
6930 for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
6931 getusint(sfd,&sm->state[i].next_state);
6932 getusint(sfd,&sm->state[i].flags);
6933 if ( sm->type == asm_context ) {
6934 sm->state[i].u.context.mark_lookup = SFD_ParseNestedLookup(sfd,sf,old);
6935 sm->state[i].u.context.cur_lookup = SFD_ParseNestedLookup(sfd,sf,old);
6936 } else if ( sm->type == asm_insert ) {
6937 getint(sfd,&temp);
6938 if ( temp==0 )
6939 sm->state[i].u.insert.mark_ins = NULL;
6940 else {
6941 sm->state[i].u.insert.mark_ins = malloc(temp+1); sm->state[i].u.insert.mark_ins[temp] = '\0';
6942 nlgetc(sfd); /* skip space */
6943 fread(sm->state[i].u.insert.mark_ins,1,temp,sfd);
6944 }
6945 getint(sfd,&temp);
6946 if ( temp==0 )
6947 sm->state[i].u.insert.cur_ins = NULL;
6948 else {
6949 sm->state[i].u.insert.cur_ins = malloc(temp+1); sm->state[i].u.insert.cur_ins[temp] = '\0';
6950 nlgetc(sfd); /* skip space */
6951 fread(sm->state[i].u.insert.cur_ins,1,temp,sfd);
6952 }
6953 } else if ( sm->type == asm_kern ) {
6954 int j;
6955 getint(sfd,&sm->state[i].u.kern.kcnt);
6956 if ( sm->state[i].u.kern.kcnt!=0 )
6957 sm->state[i].u.kern.kerns = malloc(sm->state[i].u.kern.kcnt*sizeof(int16));
6958 for ( j=0; j<sm->state[i].u.kern.kcnt; ++j ) {
6959 getint(sfd,&temp);
6960 sm->state[i].u.kern.kerns[j] = temp;
6961 }
6962 }
6963 }
6964 getname(sfd,tok); /* EndASM */
6965 }
6966
SFDParseMacNames(FILE * sfd,char * tok)6967 static struct macname *SFDParseMacNames(FILE *sfd, char *tok) {
6968 struct macname *head=NULL, *last=NULL, *cur;
6969 int enc, lang, len;
6970 char *pt;
6971 int ch;
6972
6973 while ( strcmp(tok,"MacName:")==0 ) {
6974 cur = chunkalloc(sizeof(struct macname));
6975 if ( last==NULL )
6976 head = cur;
6977 else
6978 last->next = cur;
6979 last = cur;
6980
6981 getint(sfd,&enc);
6982 getint(sfd,&lang);
6983 getint(sfd,&len);
6984 cur->enc = enc;
6985 cur->lang = lang;
6986 cur->name = pt = malloc(len+1);
6987
6988 while ( (ch=nlgetc(sfd))==' ');
6989 if ( ch=='"' )
6990 ch = nlgetc(sfd);
6991 while ( ch!='"' && ch!=EOF && pt<cur->name+len ) {
6992 if ( ch=='\\' ) {
6993 *pt = (nlgetc(sfd)-'0')<<6;
6994 *pt |= (nlgetc(sfd)-'0')<<3;
6995 *pt |= (nlgetc(sfd)-'0');
6996 } else
6997 *pt++ = ch;
6998 ch = nlgetc(sfd);
6999 }
7000 *pt = '\0';
7001 getname(sfd,tok);
7002 }
7003 return( head );
7004 }
7005
SFDParseMacFeatures(FILE * sfd,char * tok)7006 MacFeat *SFDParseMacFeatures(FILE *sfd, char *tok) {
7007 MacFeat *cur, *head=NULL, *last=NULL;
7008 struct macsetting *slast, *scur;
7009 int feat, ism, def, set;
7010
7011 while ( strcmp(tok,"MacFeat:")==0 ) {
7012 cur = chunkalloc(sizeof(MacFeat));
7013 if ( last==NULL )
7014 head = cur;
7015 else
7016 last->next = cur;
7017 last = cur;
7018
7019 getint(sfd,&feat); getint(sfd,&ism); getint(sfd, &def);
7020 cur->feature = feat; cur->ismutex = ism; cur->default_setting = def;
7021 getname(sfd,tok);
7022 cur->featname = SFDParseMacNames(sfd,tok);
7023 slast = NULL;
7024 while ( strcmp(tok,"MacSetting:")==0 ) {
7025 scur = chunkalloc(sizeof(struct macsetting));
7026 if ( slast==NULL )
7027 cur->settings = scur;
7028 else
7029 slast->next = scur;
7030 slast = scur;
7031
7032 getint(sfd,&set);
7033 scur->setting = set;
7034 getname(sfd,tok);
7035 scur->setname = SFDParseMacNames(sfd,tok);
7036 }
7037 }
7038 return( head );
7039 }
7040
SFDParseMMSubroutine(FILE * sfd)7041 static char *SFDParseMMSubroutine(FILE *sfd) {
7042 char buffer[400], *sofar=calloc(1,1);
7043 const char *endtok = "EndMMSubroutine";
7044 int len = 0, blen, first=true;
7045
7046 while ( fgets(buffer,sizeof(buffer),sfd)!=NULL ) {
7047 if ( strncmp(buffer,endtok,strlen(endtok))==0 )
7048 break;
7049 if ( first ) {
7050 first = false;
7051 if ( strcmp(buffer,"\n")==0 )
7052 continue;
7053 }
7054 blen = strlen(buffer);
7055 sofar = realloc(sofar,len+blen+1);
7056 strcpy(sofar+len,buffer);
7057 len += blen;
7058 }
7059 if ( len>0 && sofar[len-1]=='\n' )
7060 sofar[len-1] = '\0';
7061 return( sofar );
7062 }
7063
MMInferStuff(MMSet * mm)7064 static void MMInferStuff(MMSet *mm) {
7065 int i,j;
7066
7067 if ( mm==NULL )
7068 return;
7069 if ( mm->apple ) {
7070 for ( i=0; i<mm->axis_count; ++i ) {
7071 for ( j=0; j<mm->axismaps[i].points; ++j ) {
7072 real val = mm->axismaps[i].blends[j];
7073 if ( val == -1. )
7074 mm->axismaps[i].min = mm->axismaps[i].designs[j];
7075 else if ( val==0 )
7076 mm->axismaps[i].def = mm->axismaps[i].designs[j];
7077 else if ( val==1 )
7078 mm->axismaps[i].max = mm->axismaps[i].designs[j];
7079 }
7080 }
7081 }
7082 }
7083
SFDSizeMap(EncMap * map,int glyphcnt,int enccnt)7084 static void SFDSizeMap(EncMap *map,int glyphcnt,int enccnt) {
7085 if ( glyphcnt>map->backmax ) {
7086 map->backmap = realloc(map->backmap,glyphcnt*sizeof(int));
7087 memset(map->backmap+map->backmax,-1,(glyphcnt-map->backmax)*sizeof(int));
7088 map->backmax = glyphcnt;
7089 }
7090 if ( enccnt>map->encmax ) {
7091 map->map = realloc(map->map,enccnt*sizeof(int));
7092 memset(map->map+map->backmax,-1,(enccnt-map->encmax)*sizeof(int));
7093 map->encmax = map->enccount = enccnt;
7094 }
7095 }
7096
7097 static SplineFont *SFD_GetFont(FILE *sfd,SplineFont *cidmaster,char *tok,
7098 int fromdir, char *dirname, float sfdversion);
7099
SFD_FigureDirType(SplineFont * sf,char * tok,char * dirname,Encoding * enc,struct remap * remap,int had_layer_cnt)7100 static SplineFont *SFD_FigureDirType(SplineFont *sf,char *tok, char *dirname,
7101 Encoding *enc, struct remap *remap,int had_layer_cnt) {
7102 /* In a sfdir a directory will either contain glyph files */
7103 /* subfont dirs */
7104 /* instance dirs */
7105 /* (or bitmap files, but we don't care about them here */
7106 /* It will not contain some glyph and some subfont nor instance files */
7107 int gc=0, sc=0, ic=0, bc=0;
7108 DIR *dir;
7109 struct dirent *ent;
7110 char *name, *props, *pt;
7111
7112 dir = opendir(dirname);
7113 if ( dir==NULL )
7114 return( sf );
7115 sf->save_to_dir = true;
7116 while ( (ent=readdir(dir))!=NULL ) {
7117 pt = strrchr(ent->d_name,EXT_CHAR);
7118 if ( pt==NULL )
7119 /* Nothing interesting */;
7120 else if ( strcmp(pt,GLYPH_EXT)==0 )
7121 ++gc;
7122 else if ( strcmp(pt,SUBFONT_EXT)==0 )
7123 ++sc;
7124 else if ( strcmp(pt,INSTANCE_EXT)==0 )
7125 ++ic;
7126 else if ( strcmp(pt,STRIKE_EXT)==0 )
7127 ++bc;
7128 }
7129 rewinddir(dir);
7130 name = malloc(strlen(dirname)+NAME_MAX+3);
7131 props = malloc(strlen(dirname)+2*NAME_MAX+4);
7132 if ( gc!=0 ) {
7133 sf->glyphcnt = 0;
7134 sf->glyphmax = gc;
7135 sf->glyphs = calloc(gc,sizeof(SplineChar *));
7136 ff_progress_change_total(gc);
7137 if ( sf->cidmaster!=NULL ) {
7138 sf->map = sf->cidmaster->map;
7139 } else {
7140 sf->map = EncMapNew(enc->char_cnt>gc?enc->char_cnt:gc,gc,enc);
7141 sf->map->remap = remap;
7142 }
7143 SFDSizeMap(sf->map,sf->glyphcnt,enc->char_cnt>gc?enc->char_cnt:gc);
7144
7145 while ( (ent=readdir(dir))!=NULL ) {
7146 pt = strrchr(ent->d_name,EXT_CHAR);
7147 if ( pt==NULL )
7148 /* Nothing interesting */;
7149 else if ( strcmp(pt,GLYPH_EXT)==0 ) {
7150 FILE *gsfd;
7151 sprintf(name,"%s/%s", dirname, ent->d_name);
7152 gsfd = fopen(name,"r");
7153 if ( gsfd!=NULL ) {
7154 SFDGetChar(gsfd,sf,had_layer_cnt);
7155 ff_progress_next();
7156 fclose(gsfd);
7157 }
7158 }
7159 }
7160 ff_progress_next_stage();
7161 } else if ( sc!=0 ) {
7162 int i=0;
7163 sf->subfontcnt = sc;
7164 sf->subfonts = calloc(sf->subfontcnt,sizeof(SplineFont *));
7165 sf->map = EncMap1to1(1000);
7166 ff_progress_change_stages(2*sc);
7167
7168 while ( (ent=readdir(dir))!=NULL ) {
7169 pt = strrchr(ent->d_name,EXT_CHAR);
7170 if ( pt==NULL )
7171 /* Nothing interesting */;
7172 else if ( strcmp(pt,SUBFONT_EXT)==0 && i<sc ) {
7173 FILE *ssfd;
7174 sprintf(name,"%s/%s", dirname, ent->d_name);
7175 sprintf(props,"%s/" FONT_PROPS, name);
7176 ssfd = fopen(props,"r");
7177 if ( ssfd!=NULL ) {
7178 if ( i!=0 )
7179 ff_progress_next_stage();
7180 sf->subfonts[i++] = SFD_GetFont(ssfd,sf,tok,true,name,sf->sfd_version);
7181 fclose(ssfd);
7182 }
7183 }
7184 }
7185 } else if ( ic!=0 ) {
7186 MMSet *mm = sf->mm;
7187 int ipos, i=0;
7188
7189 MMInferStuff(sf->mm);
7190 ff_progress_change_stages(2*(mm->instance_count+1));
7191 while ( (ent=readdir(dir))!=NULL ) {
7192 pt = strrchr(ent->d_name,EXT_CHAR);
7193 if ( pt==NULL )
7194 /* Nothing interesting */;
7195 else if ( strcmp(pt,INSTANCE_EXT)==0 && sscanf( ent->d_name, "mm%d", &ipos)==1 ) {
7196 FILE *ssfd;
7197 if ( i!=0 )
7198 ff_progress_next_stage();
7199 sprintf(name,"%s/%s", dirname, ent->d_name);
7200 sprintf(props,"%s/" FONT_PROPS, name);
7201 ssfd = fopen(props,"r");
7202 if ( ssfd!=NULL ) {
7203 SplineFont *mmsf;
7204 mmsf = SFD_GetFont(ssfd,NULL,tok,true,name,sf->sfd_version);
7205 if ( ipos!=0 ) {
7206 EncMapFree(mmsf->map);
7207 mmsf->map=NULL;
7208 }
7209 mmsf->mm = mm;
7210 if ( ipos == 0 )
7211 mm->normal = mmsf;
7212 else
7213 mm->instances[ipos-1] = mmsf;
7214 fclose(ssfd);
7215 }
7216 }
7217 }
7218 ff_progress_next_stage();
7219 sf->mm = NULL;
7220 SplineFontFree(sf);
7221 sf = mm->normal;
7222 if ( sf->map->enc!=&custom ) {
7223 EncMap *map;
7224 MMMatchGlyphs(mm); /* sfd files from before the encoding change can have mismatched orig pos */
7225 map = EncMapFromEncoding(sf,sf->map->enc);
7226 EncMapFree(sf->map);
7227 sf->map = map;
7228 }
7229 }
7230
7231 if ( bc!=0 ) {
7232 rewinddir(dir);
7233 while ( (ent=readdir(dir))!=NULL ) {
7234 pt = strrchr(ent->d_name,EXT_CHAR);
7235 if ( pt==NULL )
7236 /* Nothing interesting */;
7237 else if ( strcmp(pt,STRIKE_EXT)==0 ) {
7238 FILE *ssfd;
7239 sprintf(name,"%s/%s", dirname, ent->d_name);
7240 sprintf(props,"%s/" STRIKE_PROPS, name);
7241 ssfd = fopen(props,"r");
7242 if ( ssfd!=NULL ) {
7243 if ( getname(ssfd,tok)==1 && strcmp(tok,"BitmapFont:")==0 )
7244 SFDGetBitmapFont(ssfd,sf,true,name);
7245 fclose(ssfd);
7246 }
7247 }
7248 }
7249 SFOrderBitmapList(sf);
7250 }
7251 closedir(dir);
7252 free(name);
7253 free(props);
7254 return( sf );
7255 }
7256
SFD_DoAltUnis(SplineFont * sf)7257 static void SFD_DoAltUnis(SplineFont *sf) {
7258 int i;
7259 struct altuni *alt;
7260 SplineChar *sc;
7261
7262 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
7263 for ( alt = sc->altuni; alt!=NULL; alt = alt->next ) {
7264 if ( alt->vs==-1 && alt->fid==0 ) {
7265 int enc = EncFromUni(alt->unienc,sf->map->enc);
7266 if ( enc!=-1 )
7267 SFDSetEncMap(sf,sc->orig_pos,enc);
7268 }
7269 }
7270 }
7271 }
7272
SFDParseLookup(FILE * sfd,OTLookup * otl)7273 static void SFDParseLookup(FILE *sfd,OTLookup *otl) {
7274 int ch;
7275 struct lookup_subtable *sub, *lastsub;
7276 FeatureScriptLangList *fl, *lastfl;
7277 struct scriptlanglist *sl, *lastsl;
7278 int i, lcnt, lmax=0;
7279 uint32 *langs=NULL;
7280 char *subname;
7281
7282 while ( (ch=nlgetc(sfd))==' ' );
7283 if ( ch=='{' ) {
7284 lastsub = NULL;
7285 while ( (subname = SFDReadUTF7Str(sfd))!=NULL ) {
7286 while ( (ch=nlgetc(sfd))==' ' );
7287 ungetc(ch,sfd);
7288 sub = chunkalloc(sizeof(struct lookup_subtable));
7289 sub->subtable_name = subname;
7290 sub->lookup = otl;
7291 switch ( otl->lookup_type ) {
7292 case gsub_single:
7293 while ( (ch=nlgetc(sfd))==' ' );
7294 if ( ch=='(' ) {
7295 sub->suffix = SFDReadUTF7Str(sfd);
7296 while ( (ch=nlgetc(sfd))==' ' );
7297 /* slurp final paren */
7298 } else
7299 ungetc(ch,sfd);
7300 sub->per_glyph_pst_or_kern = true;
7301 break;
7302 case gsub_multiple: case gsub_alternate: case gsub_ligature:
7303 case gpos_single:
7304 sub->per_glyph_pst_or_kern = true;
7305 break;
7306 case gpos_pair:
7307 if ( (ch=nlgetc(sfd))=='(' ) {
7308 ch = nlgetc(sfd);
7309 sub->vertical_kerning = (ch=='1');
7310 nlgetc(sfd); /* slurp final paren */
7311 ch=nlgetc(sfd);
7312 }
7313 if ( ch=='[' ) {
7314 getsint(sfd,&sub->separation);
7315 nlgetc(sfd); /* slurp comma */
7316 getsint(sfd,&sub->minkern);
7317 nlgetc(sfd); /* slurp comma */
7318 ch = nlgetc(sfd);
7319 sub->kerning_by_touch = ((ch-'0')&1)?1:0;
7320 sub->onlyCloser = ((ch-'0')&2)?1:0;
7321 sub->dontautokern = ((ch-'0')&4)?1:0;
7322 nlgetc(sfd); /* slurp final bracket */
7323 } else {
7324 ungetc(ch,sfd);
7325 }
7326 sub->per_glyph_pst_or_kern = true;
7327 break;
7328 case gpos_cursive: case gpos_mark2base: case gpos_mark2ligature: case gpos_mark2mark:
7329 sub->anchor_classes = true;
7330 break;
7331 default:
7332 break;
7333 }
7334 if ( lastsub==NULL )
7335 otl->subtables = sub;
7336 else
7337 lastsub->next = sub;
7338 lastsub = sub;
7339 }
7340 while ( (ch=nlgetc(sfd))==' ' );
7341 if ( ch=='}' )
7342 ch = nlgetc(sfd);
7343 }
7344 while ( ch==' ' )
7345 ch = nlgetc(sfd);
7346 if ( ch=='[' ) {
7347 lastfl = NULL;
7348 for (;;) {
7349 while ( (ch=nlgetc(sfd))==' ' );
7350 if ( ch==']' )
7351 break;
7352 fl = chunkalloc(sizeof(FeatureScriptLangList));
7353 if ( lastfl==NULL )
7354 otl->features = fl;
7355 else
7356 lastfl->next = fl;
7357 lastfl = fl;
7358 if ( ch=='<' ) {
7359 int ft=0,fs=0;
7360 fscanf(sfd,"%d,%d>", &ft, &fs );
7361 fl->ismac = true;
7362 fl->featuretag = (ft<<16) | fs;
7363 } else if ( ch=='\'' ) {
7364 ungetc(ch,sfd);
7365 fl->featuretag = gettag(sfd);
7366 }
7367 while ( (ch=nlgetc(sfd))==' ' );
7368 if ( ch=='(' ) {
7369 lastsl = NULL;
7370 for (;;) {
7371 while ( (ch=nlgetc(sfd))==' ' );
7372 if ( ch==')' )
7373 break;
7374 sl = chunkalloc(sizeof(struct scriptlanglist));
7375 if ( lastsl==NULL )
7376 fl->scripts = sl;
7377 else
7378 lastsl->next = sl;
7379 lastsl = sl;
7380 if ( ch=='\'' ) {
7381 ungetc(ch,sfd);
7382 sl->script = gettag(sfd);
7383 }
7384 while ( (ch=nlgetc(sfd))==' ' );
7385 if ( ch=='<' ) {
7386 lcnt = 0;
7387 for (;;) {
7388 while ( (ch=nlgetc(sfd))==' ' );
7389 if ( ch=='>' )
7390 break;
7391 if ( ch=='\'' ) {
7392 ungetc(ch,sfd);
7393 if ( lcnt>=lmax )
7394 langs = realloc(langs,(lmax+=10)*sizeof(uint32));
7395 langs[lcnt++] = gettag(sfd);
7396 }
7397 }
7398 sl->lang_cnt = lcnt;
7399 if ( lcnt>MAX_LANG )
7400 sl->morelangs = malloc((lcnt-MAX_LANG)*sizeof(uint32));
7401 for ( i=0; i<lcnt; ++i ) {
7402 if ( i<MAX_LANG )
7403 sl->langs[i] = langs[i];
7404 else
7405 sl->morelangs[i-MAX_LANG] = langs[i];
7406 }
7407 }
7408 }
7409 }
7410 }
7411 }
7412 free(langs);
7413 }
7414
SFDParseMathItem(FILE * sfd,SplineFont * sf,char * tok)7415 static void SFDParseMathItem(FILE *sfd,SplineFont *sf,char *tok) {
7416 /* The first five characters of a math item's keyword will be "MATH:" */
7417 /* the rest will be one of the entries in math_constants_descriptor */
7418 int i;
7419 struct MATH *math;
7420
7421 if ( (math = sf->MATH) == NULL )
7422 math = sf->MATH = calloc(1,sizeof(struct MATH));
7423 for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
7424 char *name = math_constants_descriptor[i].script_name;
7425 int len = strlen( name );
7426 if ( strncmp(tok+5,name,len)==0 && tok[5+len] == ':' && tok[6+len]=='\0' ) {
7427 int16 *pos = (int16 *) (((char *) (math)) + math_constants_descriptor[i].offset );
7428 getsint(sfd,pos);
7429 if ( math_constants_descriptor[i].devtab_offset != -1 ) {
7430 DeviceTable **devtab = (DeviceTable **) (((char *) (math)) + math_constants_descriptor[i].devtab_offset );
7431 *devtab = SFDReadDeviceTable(sfd,*devtab);
7432 break;
7433 }
7434 }
7435 }
7436 }
7437
ParseBaseLang(FILE * sfd)7438 static struct baselangextent *ParseBaseLang(FILE *sfd) {
7439 struct baselangextent *bl;
7440 struct baselangextent *cur, *last;
7441 int ch;
7442
7443 while ( (ch=nlgetc(sfd))==' ' );
7444 if ( ch=='{' ) {
7445 bl = chunkalloc(sizeof(struct baselangextent));
7446 while ( (ch=nlgetc(sfd))==' ' );
7447 ungetc(ch,sfd);
7448 if ( ch=='\'' )
7449 bl->lang = gettag(sfd); /* Lang or Feature tag, or nothing */
7450 getsint(sfd,&bl->descent);
7451 getsint(sfd,&bl->ascent);
7452 last = NULL;
7453 while ( (ch=nlgetc(sfd))==' ' );
7454 while ( ch=='{' ) {
7455 ungetc(ch,sfd);
7456 cur = ParseBaseLang(sfd);
7457 if ( last==NULL )
7458 bl->features = cur;
7459 else
7460 last->next = cur;
7461 last = cur;
7462 while ( (ch=nlgetc(sfd))==' ' );
7463 }
7464 if ( ch!='}' ) ungetc(ch,sfd);
7465 return( bl );
7466 }
7467 return( NULL );
7468 }
7469
SFDParseBaseScript(FILE * sfd,struct Base * base)7470 static struct basescript *SFDParseBaseScript(FILE *sfd,struct Base *base) {
7471 struct basescript *bs;
7472 int i, ch;
7473 struct baselangextent *last, *cur;
7474
7475 if ( base==NULL )
7476 return(NULL);
7477
7478 bs = chunkalloc(sizeof(struct basescript));
7479
7480 bs->script = gettag(sfd);
7481 getint(sfd,&bs->def_baseline);
7482 if ( base->baseline_cnt!=0 ) {
7483 bs->baseline_pos = calloc(base->baseline_cnt,sizeof(int16));
7484 for ( i=0; i<base->baseline_cnt; ++i )
7485 getsint(sfd, &bs->baseline_pos[i]);
7486 }
7487 while ( (ch=nlgetc(sfd))==' ' );
7488 last = NULL;
7489 while ( ch=='{' ) {
7490 ungetc(ch,sfd);
7491 cur = ParseBaseLang(sfd);
7492 if ( last==NULL )
7493 bs->langs = cur;
7494 else
7495 last->next = cur;
7496 last = cur;
7497 while ( (ch=nlgetc(sfd))==' ' );
7498 }
7499 return( bs );
7500 }
7501
SFDParseBase(FILE * sfd)7502 static struct Base *SFDParseBase(FILE *sfd) {
7503 struct Base *base = chunkalloc(sizeof(struct Base));
7504 int i;
7505
7506 getint(sfd,&base->baseline_cnt);
7507 if ( base->baseline_cnt!=0 ) {
7508 base->baseline_tags = malloc(base->baseline_cnt*sizeof(uint32));
7509 for ( i=0; i<base->baseline_cnt; ++i )
7510 base->baseline_tags[i] = gettag(sfd);
7511 }
7512 return( base );
7513 }
7514
SFDLookupList(FILE * sfd,SplineFont * sf)7515 static OTLookup **SFDLookupList(FILE *sfd,SplineFont *sf) {
7516 int ch;
7517 OTLookup **ret=NULL, *otl;
7518 int lcnt=0, lmax=0;
7519 char *name;
7520
7521 for (;;) {
7522 while ( (ch=nlgetc(sfd))==' ' );
7523 if ( ch=='\n' || ch==EOF )
7524 break;
7525 ungetc(ch,sfd);
7526 name = SFDReadUTF7Str(sfd);
7527 otl = SFFindLookup(sf,name);
7528 free(name);
7529 if ( otl!=NULL ) {
7530 if ( lcnt>=lmax ) {
7531 lmax += 100;
7532 ret = realloc(ret, lmax * sizeof(OTLookup *));
7533 }
7534 ret[lcnt++] = otl;
7535 }
7536 }
7537 if ( lcnt==0 )
7538 return( NULL );
7539 ret = realloc(ret, (lcnt+1) * sizeof(OTLookup *));
7540 ret[lcnt] = NULL;
7541 return( ret );
7542 }
7543
SFDParseJustify(FILE * sfd,SplineFont * sf,char * tok)7544 static void SFDParseJustify(FILE *sfd, SplineFont *sf, char *tok) {
7545 Justify *last=NULL, *cur;
7546 struct jstf_lang *jlang, *llast;
7547 int p = 0,ch;
7548
7549 while ( strcmp(tok,"Justify:")==0 ) {
7550 cur = chunkalloc(sizeof(Justify));
7551 if ( last==NULL )
7552 sf->justify = cur;
7553 else
7554 last->next = cur;
7555 last = cur;
7556 llast = jlang = NULL;
7557 cur->script = gettag(sfd);
7558 while ( getname(sfd,tok)>0 ) {
7559 if ( strcmp(tok,"Justify:")==0 || strcmp(tok,"EndJustify")==0 )
7560 break;
7561 if ( strcmp(tok,"JstfExtender:")==0 ) {
7562 while ( (ch=nlgetc(sfd))==' ' );
7563 ungetc(ch,sfd);
7564 geteol(sfd,tok);
7565 cur->extenders = copy(tok);
7566 } else if ( strcmp(tok,"JstfLang:")==0 ) {
7567 jlang = chunkalloc(sizeof(struct jstf_lang));
7568 if ( llast==NULL )
7569 cur->langs = jlang;
7570 else
7571 llast->next = jlang;
7572 llast = jlang;
7573 jlang->lang = gettag(sfd);
7574 p = -1;
7575 getint(sfd,&jlang->cnt);
7576 if ( jlang->cnt!=0 )
7577 jlang->prios = calloc(jlang->cnt,sizeof(struct jstf_prio));
7578 } else if ( strcmp(tok,"JstfPrio:")==0 ) {
7579 if ( jlang!=NULL ) {
7580 ++p;
7581 if ( p>= jlang->cnt ) {
7582 jlang->prios = realloc(jlang->prios,(p+1)*sizeof(struct jstf_prio));
7583 memset(jlang->prios+jlang->cnt,0,(p+1-jlang->cnt)*sizeof(struct jstf_prio));
7584 jlang->cnt = p+1;
7585 }
7586 }
7587 } else if ( strcmp(tok,"JstfEnableShrink:" )==0 ) {
7588 if ( p<0 ) p=0;
7589 if ( jlang!=NULL && p<jlang->cnt )
7590 jlang->prios[p].enableShrink = SFDLookupList(sfd,sf);
7591 } else if ( strcmp(tok,"JstfDisableShrink:" )==0 ) {
7592 if ( p<0 ) p=0;
7593 if ( jlang!=NULL && p<jlang->cnt )
7594 jlang->prios[p].disableShrink = SFDLookupList(sfd,sf);
7595 } else if ( strcmp(tok,"JstfMaxShrink:" )==0 ) {
7596 if ( p<0 ) p=0;
7597 if ( jlang!=NULL && p<jlang->cnt )
7598 jlang->prios[p].maxShrink = SFDLookupList(sfd,sf);
7599 } else if ( strcmp(tok,"JstfEnableExtend:" )==0 ) {
7600 if ( p<0 ) p=0;
7601 if ( jlang!=NULL && p<jlang->cnt )
7602 jlang->prios[p].enableExtend = SFDLookupList(sfd,sf);
7603 } else if ( strcmp(tok,"JstfDisableExtend:" )==0 ) {
7604 if ( p<0 ) p=0;
7605 if ( jlang!=NULL && p<jlang->cnt )
7606 jlang->prios[p].disableExtend = SFDLookupList(sfd,sf);
7607 } else if ( strcmp(tok,"JstfMaxExtend:" )==0 ) {
7608 if ( p<0 ) p=0;
7609 if ( jlang!=NULL && p<jlang->cnt )
7610 jlang->prios[p].maxExtend = SFDLookupList(sfd,sf);
7611 } else
7612 geteol(sfd,tok);
7613 }
7614 }
7615 }
7616
7617
7618
SFD_GetFontMetaDataData_Init(SFD_GetFontMetaDataData * d)7619 void SFD_GetFontMetaDataData_Init( SFD_GetFontMetaDataData* d )
7620 {
7621 memset( d, 0, sizeof(SFD_GetFontMetaDataData));
7622 }
7623
7624 /**
7625 *
7626 * @return true if the function matched the current token. If true
7627 * is returned the caller should avoid further processing of 'tok'
7628 * a return of false means that the caller might try
7629 * to handle the token with another function or drop it.
7630 */
SFD_GetFontMetaData(FILE * sfd,char * tok,SplineFont * sf,SFD_GetFontMetaDataData * d)7631 bool SFD_GetFontMetaData( FILE *sfd,
7632 char *tok,
7633 SplineFont *sf,
7634 SFD_GetFontMetaDataData* d )
7635 {
7636 int ch;
7637 int i;
7638 KernClass* kc = 0;
7639 int old;
7640 char val[2000];
7641
7642 // This allows us to assume we can dereference d
7643 // at all times
7644 static SFD_GetFontMetaDataData my_static_d;
7645 static int my_static_d_is_virgin = 1;
7646 if( !d )
7647 {
7648 if( my_static_d_is_virgin )
7649 {
7650 my_static_d_is_virgin = 0;
7651 SFD_GetFontMetaDataData_Init( &my_static_d );
7652 }
7653 d = &my_static_d;
7654 }
7655
7656 if ( strmatch(tok,"FontName:")==0 )
7657 {
7658 geteol(sfd,val);
7659 sf->fontname = copy(val);
7660 }
7661 else if ( strmatch(tok,"FullName:")==0 )
7662 {
7663 geteol(sfd,val);
7664 sf->fullname = copy(val);
7665 }
7666 else if ( strmatch(tok,"FamilyName:")==0 )
7667 {
7668 geteol(sfd,val);
7669 sf->familyname = copy(val);
7670 }
7671 else if ( strmatch(tok,"DefaultBaseFilename:")==0 )
7672 {
7673 geteol(sfd,val);
7674 sf->defbasefilename = copy(val);
7675 }
7676 else if ( strmatch(tok,"Weight:")==0 )
7677 {
7678 getprotectedname(sfd,val);
7679 sf->weight = copy(val);
7680 }
7681 else if ( strmatch(tok,"Copyright:")==0 )
7682 {
7683 sf->copyright = getquotedeol(sfd);
7684 }
7685 else if ( strmatch(tok,"Comments:")==0 )
7686 {
7687 char *temp = getquotedeol(sfd);
7688 sf->comments = latin1_2_utf8_copy(temp);
7689 free(temp);
7690 }
7691 else if ( strmatch(tok,"UComments:")==0 )
7692 {
7693 sf->comments = SFDReadUTF7Str(sfd);
7694 }
7695 else if ( strmatch(tok,"FontLog:")==0 )
7696 {
7697 sf->fontlog = SFDReadUTF7Str(sfd);
7698 }
7699 else if ( strmatch(tok,"Version:")==0 )
7700 {
7701 geteol(sfd,val);
7702 sf->version = copy(val);
7703 }
7704 else if ( strmatch(tok,"StyleMapFamilyName:")==0 )
7705 {
7706 sf->styleMapFamilyName = SFDReadUTF7Str(sfd);
7707 }
7708 /* Legacy attribute for StyleMapFamilyName. Deprecated. */
7709 else if ( strmatch(tok,"OS2FamilyName:")==0 )
7710 {
7711 if (sf->styleMapFamilyName == NULL)
7712 sf->styleMapFamilyName = SFDReadUTF7Str(sfd);
7713 }
7714 else if ( strmatch(tok,"FONDName:")==0 )
7715 {
7716 geteol(sfd,val);
7717 sf->fondname = copy(val);
7718 }
7719 else if ( strmatch(tok,"ItalicAngle:")==0 )
7720 {
7721 getreal(sfd,&sf->italicangle);
7722 }
7723 else if ( strmatch(tok,"StrokeWidth:")==0 )
7724 {
7725 getreal(sfd,&sf->strokewidth);
7726 }
7727 else if ( strmatch(tok,"UnderlinePosition:")==0 )
7728 {
7729 getreal(sfd,&sf->upos);
7730 }
7731 else if ( strmatch(tok,"UnderlineWidth:")==0 )
7732 {
7733 getreal(sfd,&sf->uwidth);
7734 }
7735 else if ( strmatch(tok,"ModificationTime:")==0 )
7736 {
7737 getlonglong(sfd,&sf->modificationtime);
7738 }
7739 else if ( strmatch(tok,"CreationTime:")==0 )
7740 {
7741 getlonglong(sfd,&sf->creationtime);
7742 d->hadtimes = true;
7743 }
7744 else if ( strmatch(tok,"PfmFamily:")==0 )
7745 {
7746 int temp;
7747 getint(sfd,&temp);
7748 sf->pfminfo.pfmfamily = temp;
7749 sf->pfminfo.pfmset = true;
7750 }
7751 else if ( strmatch(tok,"LangName:")==0 )
7752 {
7753 sf->names = SFDGetLangName(sfd,sf->names);
7754 }
7755 else if ( strmatch(tok,"GaspTable:")==0 )
7756 {
7757 SFDGetGasp(sfd,sf);
7758 }
7759 else if ( strmatch(tok,"DesignSize:")==0 )
7760 {
7761 SFDGetDesignSize(sfd,sf);
7762 }
7763 else if ( strmatch(tok,"OtfFeatName:")==0 )
7764 {
7765 SFDGetOtfFeatName(sfd,sf);
7766 }
7767 else if ( strmatch(tok,"PfmWeight:")==0 || strmatch(tok,"TTFWeight:")==0 )
7768 {
7769 getsint(sfd,&sf->pfminfo.weight);
7770 sf->pfminfo.pfmset = true;
7771 }
7772 else if ( strmatch(tok,"TTFWidth:")==0 )
7773 {
7774 getsint(sfd,&sf->pfminfo.width);
7775 sf->pfminfo.pfmset = true;
7776 }
7777 else if ( strmatch(tok,"Panose:")==0 )
7778 {
7779 int temp,i;
7780 for ( i=0; i<10; ++i )
7781 {
7782 getint(sfd,&temp);
7783 sf->pfminfo.panose[i] = temp;
7784 }
7785 sf->pfminfo.panose_set = true;
7786 }
7787 else if ( strmatch(tok,"LineGap:")==0 )
7788 {
7789 getsint(sfd,&sf->pfminfo.linegap);
7790 sf->pfminfo.pfmset = true;
7791 }
7792 else if ( strmatch(tok,"VLineGap:")==0 )
7793 {
7794 getsint(sfd,&sf->pfminfo.vlinegap);
7795 sf->pfminfo.pfmset = true;
7796 }
7797 else if ( strmatch(tok,"HheadAscent:")==0 )
7798 {
7799 getsint(sfd,&sf->pfminfo.hhead_ascent);
7800 }
7801 else if ( strmatch(tok,"HheadAOffset:")==0 )
7802 {
7803 int temp;
7804 getint(sfd,&temp); sf->pfminfo.hheadascent_add = temp;
7805 }
7806 else if ( strmatch(tok,"HheadDescent:")==0 )
7807 {
7808 getsint(sfd,&sf->pfminfo.hhead_descent);
7809 }
7810 else if ( strmatch(tok,"HheadDOffset:")==0 )
7811 {
7812 int temp;
7813 getint(sfd,&temp); sf->pfminfo.hheaddescent_add = temp;
7814 }
7815 else if ( strmatch(tok,"OS2TypoLinegap:")==0 )
7816 {
7817 getsint(sfd,&sf->pfminfo.os2_typolinegap);
7818 }
7819 else if ( strmatch(tok,"OS2TypoAscent:")==0 )
7820 {
7821 getsint(sfd,&sf->pfminfo.os2_typoascent);
7822 }
7823 else if ( strmatch(tok,"OS2TypoAOffset:")==0 )
7824 {
7825 int temp;
7826 getint(sfd,&temp); sf->pfminfo.typoascent_add = temp;
7827 }
7828 else if ( strmatch(tok,"OS2TypoDescent:")==0 )
7829 {
7830 getsint(sfd,&sf->pfminfo.os2_typodescent);
7831 }
7832 else if ( strmatch(tok,"OS2TypoDOffset:")==0 )
7833 {
7834 int temp;
7835 getint(sfd,&temp); sf->pfminfo.typodescent_add = temp;
7836 }
7837 else if ( strmatch(tok,"OS2WinAscent:")==0 )
7838 {
7839 getsint(sfd,&sf->pfminfo.os2_winascent);
7840 }
7841 else if ( strmatch(tok,"OS2WinDescent:")==0 )
7842 {
7843 getsint(sfd,&sf->pfminfo.os2_windescent);
7844 }
7845 else if ( strmatch(tok,"OS2WinAOffset:")==0 )
7846 {
7847 int temp;
7848 getint(sfd,&temp); sf->pfminfo.winascent_add = temp;
7849 }
7850 else if ( strmatch(tok,"OS2WinDOffset:")==0 )
7851 {
7852 int temp;
7853 getint(sfd,&temp); sf->pfminfo.windescent_add = temp;
7854 }
7855 else if ( strmatch(tok,"HHeadAscent:")==0 )
7856 {
7857 // DUPLICATE OF ABOVE
7858 getsint(sfd,&sf->pfminfo.hhead_ascent);
7859 }
7860 else if ( strmatch(tok,"HHeadDescent:")==0 )
7861 {
7862 // DUPLICATE OF ABOVE
7863 getsint(sfd,&sf->pfminfo.hhead_descent);
7864 }
7865
7866 else if ( strmatch(tok,"HHeadAOffset:")==0 )
7867 {
7868 // DUPLICATE OF ABOVE
7869 int temp;
7870 getint(sfd,&temp); sf->pfminfo.hheadascent_add = temp;
7871 }
7872 else if ( strmatch(tok,"HHeadDOffset:")==0 )
7873 {
7874 // DUPLICATE OF ABOVE
7875 int temp;
7876 getint(sfd,&temp); sf->pfminfo.hheaddescent_add = temp;
7877 }
7878 else if ( strmatch(tok,"MacStyle:")==0 )
7879 {
7880 getsint(sfd,&sf->macstyle);
7881 }
7882 else if ( strmatch(tok,"OS2SubXSize:")==0 )
7883 {
7884 getsint(sfd,&sf->pfminfo.os2_subxsize);
7885 sf->pfminfo.subsuper_set = true;
7886 }
7887 else if ( strmatch(tok,"OS2SubYSize:")==0 )
7888 {
7889 getsint(sfd,&sf->pfminfo.os2_subysize);
7890 }
7891 else if ( strmatch(tok,"OS2SubXOff:")==0 )
7892 {
7893 getsint(sfd,&sf->pfminfo.os2_subxoff);
7894 }
7895 else if ( strmatch(tok,"OS2SubYOff:")==0 )
7896 {
7897 getsint(sfd,&sf->pfminfo.os2_subyoff);
7898 }
7899 else if ( strmatch(tok,"OS2SupXSize:")==0 )
7900 {
7901 getsint(sfd,&sf->pfminfo.os2_supxsize);
7902 }
7903 else if ( strmatch(tok,"OS2SupYSize:")==0 )
7904 {
7905 getsint(sfd,&sf->pfminfo.os2_supysize);
7906 }
7907 else if ( strmatch(tok,"OS2SupXOff:")==0 )
7908 {
7909 getsint(sfd,&sf->pfminfo.os2_supxoff);
7910 }
7911 else if ( strmatch(tok,"OS2SupYOff:")==0 )
7912 {
7913 getsint(sfd,&sf->pfminfo.os2_supyoff);
7914 }
7915 else if ( strmatch(tok,"OS2StrikeYSize:")==0 )
7916 {
7917 getsint(sfd,&sf->pfminfo.os2_strikeysize);
7918 }
7919 else if ( strmatch(tok,"OS2StrikeYPos:")==0 )
7920 {
7921 getsint(sfd,&sf->pfminfo.os2_strikeypos);
7922 }
7923 else if ( strmatch(tok,"OS2CapHeight:")==0 )
7924 {
7925 getsint(sfd,&sf->pfminfo.os2_capheight);
7926 }
7927 else if ( strmatch(tok,"OS2XHeight:")==0 )
7928 {
7929 getsint(sfd,&sf->pfminfo.os2_xheight);
7930 }
7931 else if ( strmatch(tok,"OS2FamilyClass:")==0 )
7932 {
7933 getsint(sfd,&sf->pfminfo.os2_family_class);
7934 }
7935 else if ( strmatch(tok,"OS2Vendor:")==0 )
7936 {
7937 while ( isspace(nlgetc(sfd)));
7938 sf->pfminfo.os2_vendor[0] = nlgetc(sfd);
7939 sf->pfminfo.os2_vendor[1] = nlgetc(sfd);
7940 sf->pfminfo.os2_vendor[2] = nlgetc(sfd);
7941 sf->pfminfo.os2_vendor[3] = nlgetc(sfd);
7942 (void) nlgetc(sfd);
7943 }
7944 else if ( strmatch(tok,"OS2CodePages:")==0 )
7945 {
7946 gethexints(sfd,sf->pfminfo.codepages,2);
7947 sf->pfminfo.hascodepages = true;
7948 }
7949 else if ( strmatch(tok,"OS2UnicodeRanges:")==0 )
7950 {
7951 gethexints(sfd,sf->pfminfo.unicoderanges,4);
7952 sf->pfminfo.hasunicoderanges = true;
7953 }
7954 else if ( strmatch(tok,"TopEncoding:")==0 )
7955 {
7956 /* Obsolete */
7957 getint(sfd,&sf->top_enc);
7958 }
7959 else if ( strmatch(tok,"Ascent:")==0 )
7960 {
7961 getint(sfd,&sf->ascent);
7962 }
7963 else if ( strmatch(tok,"Descent:")==0 )
7964 {
7965 getint(sfd,&sf->descent);
7966 }
7967 else if ( strmatch(tok,"InvalidEm:")==0 )
7968 {
7969 getint(sfd,&sf->invalidem);
7970 }
7971 else if ( strmatch(tok,"woffMajor:")==0 )
7972 {
7973 getint(sfd,&sf->woffMajor);
7974 }
7975 else if ( strmatch(tok,"woffMinor:")==0 )
7976 {
7977 getint(sfd,&sf->woffMinor);
7978 }
7979 else if ( strmatch(tok,"woffMetadata:")==0 )
7980 {
7981 sf->woffMetadata = SFDReadUTF7Str(sfd);
7982 }
7983 else if ( strmatch(tok,"UFOAscent:")==0 )
7984 {
7985 getreal(sfd,&sf->ufo_ascent);
7986 }
7987 else if ( strmatch(tok,"UFODescent:")==0 )
7988 {
7989 getreal(sfd,&sf->ufo_descent);
7990 }
7991 else if ( strmatch(tok,"sfntRevision:")==0 )
7992 {
7993 gethex(sfd,(uint32 *)&sf->sfntRevision);
7994 }
7995 else if ( strmatch(tok,"LayerCount:")==0 )
7996 {
7997 d->had_layer_cnt = true;
7998 int layer_cnt_tmp;
7999 getint(sfd,&layer_cnt_tmp);
8000 if ( layer_cnt_tmp>2 ) {
8001 sf->layer_cnt = layer_cnt_tmp;
8002 sf->layers = realloc(sf->layers,sf->layer_cnt*sizeof(LayerInfo));
8003 memset(sf->layers+2,0,(sf->layer_cnt-2)*sizeof(LayerInfo));
8004 }
8005 }
8006 else if ( strmatch(tok,"Layer:")==0 )
8007 {
8008 // TODO: Read the U. F. O. path.
8009 int layer, o2, bk;
8010 getint(sfd,&layer);
8011 if ( layer>=sf->layer_cnt ) {
8012 sf->layers = realloc(sf->layers,(layer+1)*sizeof(LayerInfo));
8013 memset(sf->layers+sf->layer_cnt,0,((layer+1)-sf->layer_cnt)*sizeof(LayerInfo));
8014 sf->layer_cnt = layer+1;
8015 }
8016 getint(sfd,&o2);
8017 sf->layers[layer].order2 = o2;
8018 sf->layers[layer].background = layer==ly_back;
8019 /* Used briefly, now background is after layer name */
8020 while ( (ch=nlgetc(sfd))==' ' );
8021 ungetc(ch,sfd);
8022 if ( ch!='"' ) {
8023 getint(sfd,&bk);
8024 sf->layers[layer].background = bk;
8025 }
8026 /* end of section for obsolete format */
8027 sf->layers[layer].name = SFDReadUTF7Str(sfd);
8028 while ( (ch=nlgetc(sfd))==' ' );
8029 ungetc(ch,sfd);
8030 if ( ch!='\n' ) {
8031 getint(sfd,&bk);
8032 sf->layers[layer].background = bk;
8033 }
8034 while ( (ch=nlgetc(sfd))==' ' );
8035 ungetc(ch,sfd);
8036 if ( ch!='\n' ) { sf->layers[layer].ufo_path = SFDReadUTF7Str(sfd); }
8037 }
8038 else if ( strmatch(tok,"PreferredKerning:")==0 )
8039 {
8040 int temp;
8041 getint(sfd,&temp);
8042 sf->preferred_kerning = temp;
8043 }
8044 else if ( strmatch(tok,"StrokedFont:")==0 )
8045 {
8046 int temp;
8047 getint(sfd,&temp);
8048 sf->strokedfont = temp;
8049 }
8050 else if ( strmatch(tok,"MultiLayer:")==0 )
8051 {
8052 int temp;
8053 getint(sfd,&temp);
8054 sf->multilayer = temp;
8055 }
8056 else if ( strmatch(tok,"NeedsXUIDChange:")==0 )
8057 {
8058 int temp;
8059 getint(sfd,&temp);
8060 sf->changed_since_xuidchanged = temp;
8061 }
8062 else if ( strmatch(tok,"VerticalOrigin:")==0 )
8063 {
8064 // this doesn't seem to be written ever.
8065 int temp;
8066 getint(sfd,&temp);
8067 sf->hasvmetrics = true;
8068 }
8069 else if ( strmatch(tok,"HasVMetrics:")==0 )
8070 {
8071 int temp;
8072 getint(sfd,&temp);
8073 sf->hasvmetrics = temp;
8074 }
8075 else if ( strmatch(tok,"Justify:")==0 )
8076 {
8077 SFDParseJustify(sfd,sf,tok);
8078 }
8079 else if ( strmatch(tok,"BaseHoriz:")==0 )
8080 {
8081 sf->horiz_base = SFDParseBase(sfd);
8082 d->last_base = sf->horiz_base;
8083 d->last_base_script = NULL;
8084 }
8085 else if ( strmatch(tok,"BaseVert:")==0 )
8086 {
8087 sf->vert_base = SFDParseBase(sfd);
8088 d->last_base = sf->vert_base;
8089 d->last_base_script = NULL;
8090 }
8091 else if ( strmatch(tok,"BaseScript:")==0 )
8092 {
8093 struct basescript *bs = SFDParseBaseScript(sfd,d->last_base);
8094 if ( d->last_base==NULL )
8095 {
8096 BaseScriptFree(bs);
8097 bs = NULL;
8098 }
8099 else if ( d->last_base_script!=NULL )
8100 d->last_base_script->next = bs;
8101 else
8102 d->last_base->scripts = bs;
8103 d->last_base_script = bs;
8104 }
8105 else if ( strmatch(tok,"StyleMap:")==0 )
8106 {
8107 uint32 u;
8108 gethex(sfd,&u);
8109 sf->pfminfo.stylemap = u;
8110 }
8111 /* Legacy attribute for StyleMap. Deprecated. */
8112 else if ( strmatch(tok,"OS2StyleName:")==0 )
8113 {
8114 char* sname = SFDReadUTF7Str(sfd);
8115 if (sf->pfminfo.stylemap == -1) {
8116 if (strcmp(sname,"bold italic")==0) sf->pfminfo.stylemap = 0x21;
8117 else if (strcmp(sname,"bold")==0) sf->pfminfo.stylemap = 0x20;
8118 else if (strcmp(sname,"italic")==0) sf->pfminfo.stylemap = 0x01;
8119 else if (strcmp(sname,"regular")==0) sf->pfminfo.stylemap = 0x40;
8120 }
8121 free(sname);
8122 }
8123 else if ( strmatch(tok,"FSType:")==0 )
8124 {
8125 getsint(sfd,&sf->pfminfo.fstype);
8126 }
8127 else if ( strmatch(tok,"OS2Version:")==0 )
8128 {
8129 getsint(sfd,&sf->os2_version);
8130 }
8131 else if ( strmatch(tok,"OS2_WeightWidthSlopeOnly:")==0 )
8132 {
8133 int temp;
8134 getint(sfd,&temp);
8135 sf->weight_width_slope_only = temp;
8136 }
8137 else if ( strmatch(tok,"OS2_UseTypoMetrics:")==0 )
8138 {
8139 int temp;
8140 getint(sfd,&temp);
8141 sf->use_typo_metrics = temp;
8142 }
8143 else if ( strmatch(tok,"UseUniqueID:")==0 )
8144 {
8145 int temp;
8146 getint(sfd,&temp);
8147 sf->use_uniqueid = temp;
8148 }
8149 else if ( strmatch(tok,"UseXUID:")==0 )
8150 {
8151 int temp;
8152 getint(sfd,&temp);
8153 sf->use_xuid = temp;
8154 }
8155 else if ( strmatch(tok,"UniqueID:")==0 )
8156 {
8157 getint(sfd,&sf->uniqueid);
8158 }
8159 else if ( strmatch(tok,"XUID:")==0 )
8160 {
8161 geteol(sfd,tok);
8162 sf->xuid = copy(tok);
8163 }
8164 else if ( strmatch(tok,"Lookup:")==0 )
8165 {
8166 OTLookup *otl;
8167 int temp;
8168 if ( sf->sfd_version<2 ) {
8169 IError( "Lookups should not happen in version 1 sfd files." );
8170 exit(1);
8171 }
8172 otl = chunkalloc(sizeof(OTLookup));
8173 getint(sfd,&temp); otl->lookup_type = temp;
8174 getint(sfd,&temp); otl->lookup_flags = temp;
8175 getint(sfd,&temp); otl->store_in_afm = temp;
8176 otl->lookup_name = SFDReadUTF7Str(sfd);
8177 if ( otl->lookup_type<gpos_single ) {
8178 if ( d->lastsotl==NULL )
8179 sf->gsub_lookups = otl;
8180 else
8181 d->lastsotl->next = otl;
8182 d->lastsotl = otl;
8183 } else {
8184 if ( d->lastpotl==NULL )
8185 sf->gpos_lookups = otl;
8186 else
8187 d->lastpotl->next = otl;
8188 d->lastpotl = otl;
8189 }
8190 SFDParseLookup(sfd,otl);
8191 }
8192 else if ( strmatch(tok,"MarkAttachClasses:")==0 )
8193 {
8194 getint(sfd,&sf->mark_class_cnt);
8195 sf->mark_classes = malloc(sf->mark_class_cnt*sizeof(char *));
8196 sf->mark_class_names = malloc(sf->mark_class_cnt*sizeof(char *));
8197 sf->mark_classes[0] = NULL; sf->mark_class_names[0] = NULL;
8198 for ( i=1; i<sf->mark_class_cnt; ++i )
8199 {
8200 /* Class 0 is unused */
8201 int temp;
8202 while ( (temp=nlgetc(sfd))=='\n' || temp=='\r' ); ungetc(temp,sfd);
8203 sf->mark_class_names[i] = SFDReadUTF7Str(sfd);
8204 getint(sfd,&temp);
8205 sf->mark_classes[i] = malloc(temp+1); sf->mark_classes[i][temp] = '\0';
8206 nlgetc(sfd); /* skip space */
8207 fread(sf->mark_classes[i],1,temp,sfd);
8208 }
8209 }
8210 else if ( strmatch(tok,"MarkAttachSets:")==0 )
8211 {
8212 getint(sfd,&sf->mark_set_cnt);
8213 sf->mark_sets = malloc(sf->mark_set_cnt*sizeof(char *));
8214 sf->mark_set_names = malloc(sf->mark_set_cnt*sizeof(char *));
8215 for ( i=0; i<sf->mark_set_cnt; ++i )
8216 {
8217 /* Set 0 is used */
8218 int temp;
8219 while ( (temp=nlgetc(sfd))=='\n' || temp=='\r' ); ungetc(temp,sfd);
8220 sf->mark_set_names[i] = SFDReadUTF7Str(sfd);
8221 getint(sfd,&temp);
8222 sf->mark_sets[i] = malloc(temp+1); sf->mark_sets[i][temp] = '\0';
8223 nlgetc(sfd); /* skip space */
8224 fread(sf->mark_sets[i],1,temp,sfd);
8225 }
8226 }
8227 else if ( strmatch(tok,"KernClass2:")==0 || strmatch(tok,"VKernClass2:")==0 ||
8228 strmatch(tok,"KernClass:")==0 || strmatch(tok,"VKernClass:")==0 ||
8229 strmatch(tok,"KernClass3:")==0 || strmatch(tok,"VKernClass3:")==0 )
8230 {
8231 int kernclassversion = 0;
8232 int isv = tok[0]=='V';
8233 int kcvoffset = (isv ? 10 : 9); //Offset to read kerning class version
8234 if (isdigit(tok[kcvoffset])) kernclassversion = tok[kcvoffset] - '0';
8235 int temp, classstart=1;
8236 int old = (kernclassversion == 0);
8237
8238 if ( (sf->sfd_version<2)!=old ) {
8239 IError( "Version mixup in Kerning Classes of sfd file." );
8240 exit(1);
8241 }
8242 kc = chunkalloc(old ? sizeof(KernClass1) : sizeof(KernClass));
8243 getint(sfd,&kc->first_cnt);
8244 ch=nlgetc(sfd);
8245 if ( ch=='+' )
8246 classstart = 0;
8247 else
8248 ungetc(ch,sfd);
8249 getint(sfd,&kc->second_cnt);
8250 if ( old ) {
8251 getint(sfd,&temp); ((KernClass1 *) kc)->sli = temp;
8252 getint(sfd,&temp); ((KernClass1 *) kc)->flags = temp;
8253 } else {
8254 kc->subtable = SFFindLookupSubtableAndFreeName(sf,SFDReadUTF7Str(sfd));
8255 if ( kc->subtable!=NULL && kc->subtable->kc==NULL )
8256 kc->subtable->kc = kc;
8257 else {
8258 if ( kc->subtable==NULL )
8259 LogError(_("Bad SFD file, missing subtable in kernclass defn.\n") );
8260 else
8261 LogError(_("Bad SFD file, two kerning classes assigned to the same subtable: %s\n"), kc->subtable->subtable_name );
8262 kc->subtable = NULL;
8263 }
8264 }
8265 kc->firsts = calloc(kc->first_cnt,sizeof(char *));
8266 kc->seconds = calloc(kc->second_cnt,sizeof(char *));
8267 kc->offsets = calloc(kc->first_cnt*kc->second_cnt,sizeof(int16));
8268 kc->adjusts = calloc(kc->first_cnt*kc->second_cnt,sizeof(DeviceTable));
8269 if (kernclassversion >= 3) {
8270 kc->firsts_flags = calloc(kc->first_cnt, sizeof(int));
8271 kc->seconds_flags = calloc(kc->second_cnt, sizeof(int));
8272 kc->offsets_flags = calloc(kc->first_cnt*kc->second_cnt, sizeof(int));
8273 kc->firsts_names = calloc(kc->first_cnt, sizeof(char*));
8274 kc->seconds_names = calloc(kc->second_cnt, sizeof(char*));
8275 }
8276 kc->firsts[0] = NULL;
8277 for ( i=classstart; i<kc->first_cnt; ++i ) {
8278 if (kernclassversion < 3) {
8279 getint(sfd,&temp);
8280 kc->firsts[i] = malloc(temp+1); kc->firsts[i][temp] = '\0';
8281 nlgetc(sfd); /* skip space */
8282 fread(kc->firsts[i],1,temp,sfd);
8283 } else {
8284 getint(sfd,&kc->firsts_flags[i]);
8285 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd); if (ch == '\n' || ch == EOF) continue;
8286 kc->firsts_names[i] = SFDReadUTF7Str(sfd);
8287 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd); if (ch == '\n' || ch == EOF) continue;
8288 kc->firsts[i] = SFDReadUTF7Str(sfd);
8289 if (kc->firsts[i] == NULL) kc->firsts[i] = copy(""); // In certain places, this must be defined.
8290 while ((ch=nlgetc(sfd)) == ' ' || ch == '\n'); ungetc(ch, sfd);
8291 }
8292 }
8293 kc->seconds[0] = NULL;
8294 for ( i=1; i<kc->second_cnt; ++i ) {
8295 if (kernclassversion < 3) {
8296 getint(sfd,&temp);
8297 kc->seconds[i] = malloc(temp+1); kc->seconds[i][temp] = '\0';
8298 nlgetc(sfd); /* skip space */
8299 fread(kc->seconds[i],1,temp,sfd);
8300 } else {
8301 getint(sfd,&temp);
8302 kc->seconds_flags[i] = temp;
8303 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd); if (ch == '\n' || ch == EOF) continue;
8304 kc->seconds_names[i] = SFDReadUTF7Str(sfd);
8305 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd); if (ch == '\n' || ch == EOF) continue;
8306 kc->seconds[i] = SFDReadUTF7Str(sfd);
8307 if (kc->seconds[i] == NULL) kc->seconds[i] = copy(""); // In certain places, this must be defined.
8308 while ((ch=nlgetc(sfd)) == ' ' || ch == '\n'); ungetc(ch, sfd);
8309 }
8310 }
8311 for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
8312 if (kernclassversion >= 3) {
8313 getint(sfd,&temp);
8314 kc->offsets_flags[i] = temp;
8315 }
8316 getint(sfd,&temp);
8317 kc->offsets[i] = temp;
8318 SFDReadDeviceTable(sfd,&kc->adjusts[i]);
8319 }
8320 if ( !old && kc->subtable == NULL ) {
8321 /* Error. Ignore it. Free it. Whatever */;
8322 } else if ( !isv ) {
8323 if ( d->lastkc==NULL )
8324 sf->kerns = kc;
8325 else
8326 d->lastkc->next = kc;
8327 d->lastkc = kc;
8328 } else {
8329 if ( d->lastvkc==NULL )
8330 sf->vkerns = kc;
8331 else
8332 d->lastvkc->next = kc;
8333 d->lastvkc = kc;
8334 }
8335 }
8336 else if ( strmatch(tok,"ContextPos2:")==0 || strmatch(tok,"ContextSub2:")==0 ||
8337 strmatch(tok,"ChainPos2:")==0 || strmatch(tok,"ChainSub2:")==0 ||
8338 strmatch(tok,"ReverseChain2:")==0 ||
8339 strmatch(tok,"ContextPos:")==0 || strmatch(tok,"ContextSub:")==0 ||
8340 strmatch(tok,"ChainPos:")==0 || strmatch(tok,"ChainSub:")==0 ||
8341 strmatch(tok,"ReverseChain:")==0 )
8342 {
8343 FPST *fpst;
8344 int old;
8345 if ( strchr(tok,'2')!=NULL ) {
8346 old = false;
8347 fpst = chunkalloc(sizeof(FPST));
8348 } else {
8349 old = true;
8350 fpst = chunkalloc(sizeof(FPST1));
8351 }
8352 if ( (sf->sfd_version<2)!=old ) {
8353 IError( "Version mixup in FPST of sfd file." );
8354 exit(1);
8355 }
8356 if ( d->lastfp==NULL )
8357 sf->possub = fpst;
8358 else
8359 d->lastfp->next = fpst;
8360 d->lastfp = fpst;
8361 SFDParseChainContext(sfd,sf,fpst,tok,old);
8362 }
8363 else if ( strmatch(tok,"Group:")==0 ) {
8364 struct ff_glyphclasses *grouptmp = calloc(1, sizeof(struct ff_glyphclasses));
8365 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8366 grouptmp->classname = SFDReadUTF7Str(sfd);
8367 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8368 grouptmp->glyphs = SFDReadUTF7Str(sfd);
8369 while ((ch=nlgetc(sfd)) == ' ' || ch == '\n'); ungetc(ch, sfd);
8370 if (d->lastgroup != NULL) d->lastgroup->next = grouptmp; else sf->groups = grouptmp;
8371 d->lastgroup = grouptmp;
8372 }
8373 else if ( strmatch(tok,"GroupKern:")==0 ) {
8374 int temp = 0;
8375 struct ff_rawoffsets *kerntmp = calloc(1, sizeof(struct ff_rawoffsets));
8376 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8377 kerntmp->left = SFDReadUTF7Str(sfd);
8378 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8379 kerntmp->right = SFDReadUTF7Str(sfd);
8380 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8381 getint(sfd,&temp);
8382 kerntmp->offset = temp;
8383 while ((ch=nlgetc(sfd)) == ' ' || ch == '\n'); ungetc(ch, sfd);
8384 if (d->lastgroupkern != NULL) d->lastgroupkern->next = kerntmp; else sf->groupkerns = kerntmp;
8385 d->lastgroupkern = kerntmp;
8386 }
8387 else if ( strmatch(tok,"GroupVKern:")==0 ) {
8388 int temp = 0;
8389 struct ff_rawoffsets *kerntmp = calloc(1, sizeof(struct ff_rawoffsets));
8390 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8391 kerntmp->left = SFDReadUTF7Str(sfd);
8392 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8393 kerntmp->right = SFDReadUTF7Str(sfd);
8394 while ((ch=nlgetc(sfd)) == ' '); ungetc(ch, sfd);
8395 getint(sfd,&temp);
8396 kerntmp->offset = temp;
8397 while ((ch=nlgetc(sfd)) == ' ' || ch == '\n'); ungetc(ch, sfd);
8398 if (d->lastgroupvkern != NULL) d->lastgroupvkern->next = kerntmp; else sf->groupvkerns = kerntmp;
8399 d->lastgroupvkern = kerntmp;
8400 }
8401 else if ( strmatch(tok,"MacIndic2:")==0 || strmatch(tok,"MacContext2:")==0 ||
8402 strmatch(tok,"MacLigature2:")==0 || strmatch(tok,"MacSimple2:")==0 ||
8403 strmatch(tok,"MacKern2:")==0 || strmatch(tok,"MacInsert2:")==0 ||
8404 strmatch(tok,"MacIndic:")==0 || strmatch(tok,"MacContext:")==0 ||
8405 strmatch(tok,"MacLigature:")==0 || strmatch(tok,"MacSimple:")==0 ||
8406 strmatch(tok,"MacKern:")==0 || strmatch(tok,"MacInsert:")==0 )
8407 {
8408 ASM *sm;
8409 if ( strchr(tok,'2')!=NULL ) {
8410 old = false;
8411 sm = chunkalloc(sizeof(ASM));
8412 } else {
8413 old = true;
8414 sm = chunkalloc(sizeof(ASM1));
8415 }
8416 if ( (sf->sfd_version<2)!=old ) {
8417 IError( "Version mixup in state machine of sfd file." );
8418 exit(1);
8419 }
8420 if ( d->lastsm==NULL )
8421 sf->sm = sm;
8422 else
8423 d->lastsm->next = sm;
8424 d->lastsm = sm;
8425 SFDParseStateMachine(sfd,sf,sm,tok,old);
8426 }
8427 else if ( strmatch(tok,"MacFeat:")==0 )
8428 {
8429 sf->features = SFDParseMacFeatures(sfd,tok);
8430 }
8431 else if ( strmatch(tok,"TtfTable:")==0 )
8432 {
8433 /* Old, binary format */
8434 /* still used for maxp and unknown tables */
8435 SFDGetTtfTable(sfd,sf,d->lastttf);
8436 }
8437 else if ( strmatch(tok,"TtTable:")==0 )
8438 {
8439 /* text instruction format */
8440 SFDGetTtTable(sfd,sf,d->lastttf);
8441 }
8442
8443
8444 ///////////////////
8445
8446 else if ( strmatch(tok,"ShortTable:")==0 )
8447 {
8448 // only read, not written.
8449 /* text number format */
8450 SFDGetShortTable(sfd,sf,d->lastttf);
8451 }
8452 else
8453 {
8454 //
8455 // We didn't have a match ourselves.
8456 //
8457 return false;
8458 }
8459 return true;
8460 }
8461
SFD_GetFontMetaDataVoid(FILE * sfd,char * tok,SplineFont * sf,void * d)8462 void SFD_GetFontMetaDataVoid( FILE *sfd,
8463 char *tok,
8464 SplineFont *sf,
8465 void* d ) {
8466 SFD_GetFontMetaData(sfd, tok, sf, d);
8467 }
8468
SFD_GetFont(FILE * sfd,SplineFont * cidmaster,char * tok,int fromdir,char * dirname,float sfdversion)8469 static SplineFont *SFD_GetFont( FILE *sfd,SplineFont *cidmaster,char *tok,
8470 int fromdir, char *dirname, float sfdversion )
8471 {
8472 SplineFont *sf;
8473 int realcnt, i, eof, mappos=-1, ch;
8474 struct table_ordering *lastord = NULL;
8475 struct axismap *lastaxismap = NULL;
8476 struct named_instance *lastnamedinstance = NULL;
8477 int pushedbacktok = false;
8478 Encoding *enc = &custom;
8479 struct remap *remap = NULL;
8480 int haddupenc;
8481 int old_style_order2 = false;
8482 int had_layer_cnt=false;
8483
8484 orig_pos = 0; /* Only used for compatibility with extremely old sfd files */
8485
8486 sf = SplineFontEmpty();
8487 if ( sfdversion>0 && sfdversion<2 ) {
8488 /* If it's an old style sfd file with old style features we need some */
8489 /* extra data space to do the conversion from old to new */
8490 sf = realloc(sf,sizeof(SplineFont1));
8491 memset(((uint8 *) sf) + sizeof(SplineFont),0,sizeof(SplineFont1)-sizeof(SplineFont));
8492 }
8493 sf->sfd_version = sfdversion;
8494 sf->cidmaster = cidmaster;
8495 sf->uni_interp = ui_unset;
8496 SFD_GetFontMetaDataData d;
8497 SFD_GetFontMetaDataData_Init( &d );
8498 while ( 1 ) {
8499 if ( pushedbacktok )
8500 pushedbacktok = false;
8501 else if ( (eof = getname(sfd,tok))!=1 ) {
8502 if ( eof==-1 )
8503 break;
8504 geteol(sfd,tok);
8505 continue;
8506 }
8507
8508
8509 bool wasMetadata = SFD_GetFontMetaData( sfd, tok, sf, &d );
8510 had_layer_cnt = d.had_layer_cnt;
8511 if( wasMetadata )
8512 {
8513 // we have handled the token entirely
8514 // inside SFD_GetFontMetaData() move to next token.
8515 continue;
8516 }
8517
8518
8519 if ( strmatch(tok,"DisplaySize:")==0 )
8520 {
8521 getint(sfd,&sf->display_size);
8522 }
8523 else if ( strmatch(tok,"DisplayLayer:")==0 )
8524 {
8525 getint(sfd,&sf->display_layer);
8526 }
8527 else if ( strmatch(tok,"ExtremaBound:")==0 )
8528 {
8529 getint(sfd,&sf->extrema_bound);
8530 }
8531 else if ( strmatch(tok,"WidthSeparation:")==0 )
8532 {
8533 getint(sfd,&sf->width_separation);
8534 }
8535 else if ( strmatch(tok,"WinInfo:")==0 )
8536 {
8537 int temp1, temp2;
8538 getint(sfd,&sf->top_enc);
8539 getint(sfd,&temp1);
8540 getint(sfd,&temp2);
8541 if ( sf->top_enc<=0 ) sf->top_enc=-1;
8542 if ( temp1<=0 ) temp1 = 16;
8543 if ( temp2<=0 ) temp2 = 4;
8544 sf->desired_col_cnt = temp1;
8545 sf->desired_row_cnt = temp2;
8546 }
8547 else if ( strmatch(tok,"AntiAlias:")==0 )
8548 {
8549 int temp;
8550 getint(sfd,&temp);
8551 sf->display_antialias = temp;
8552 }
8553 else if ( strmatch(tok,"FitToEm:")==0 )
8554 {
8555 int temp;
8556 getint(sfd,&temp);
8557 sf->display_bbsized = temp;
8558 }
8559 else if ( strmatch(tok,"OnlyBitmaps:")==0 )
8560 {
8561 int temp;
8562 getint(sfd,&temp);
8563 sf->onlybitmaps = temp;
8564 }
8565 else if ( strmatch(tok,"Order2:")==0 )
8566 {
8567 getint(sfd,&old_style_order2);
8568 sf->grid.order2 = old_style_order2;
8569 sf->layers[ly_back].order2 = old_style_order2;
8570 sf->layers[ly_fore].order2 = old_style_order2;
8571 }
8572 else if ( strmatch(tok,"GridOrder2:")==0 )
8573 {
8574 int o2;
8575 getint(sfd,&o2);
8576 sf->grid.order2 = o2;
8577 }
8578 else if ( strmatch(tok,"Encoding:")==0 )
8579 {
8580 enc = SFDGetEncoding(sfd,tok);
8581 if ( sf->map!=NULL ) sf->map->enc = enc;
8582 }
8583 else if ( strmatch(tok,"OldEncoding:")==0 )
8584 {
8585 /* old_encname =*/ (void) SFDGetEncoding(sfd,tok);
8586 }
8587 else if ( strmatch(tok,"UnicodeInterp:")==0 )
8588 {
8589 sf->uni_interp = SFDGetUniInterp(sfd,tok,sf);
8590 }
8591 else if ( strmatch(tok,"NameList:")==0 )
8592 {
8593 SFDGetNameList(sfd,tok,sf);
8594 }
8595 else if ( strmatch(tok,"Compacted:")==0 )
8596 {
8597 int temp;
8598 getint(sfd,&temp);
8599 sf->compacted = temp;
8600 }
8601 else if ( strmatch(tok,"Registry:")==0 )
8602 {
8603 geteol(sfd,tok);
8604 sf->cidregistry = copy(tok);
8605 }
8606
8607
8608 //////////
8609
8610
8611 else if ( strmatch(tok,"Ordering:")==0 ) {
8612 geteol(sfd,tok);
8613 sf->ordering = copy(tok);
8614 } else if ( strmatch(tok,"Supplement:")==0 ) {
8615 getint(sfd,&sf->supplement);
8616 } else if ( strmatch(tok,"RemapN:")==0 ) {
8617 int n;
8618 getint(sfd,&n);
8619 remap = calloc(n+1,sizeof(struct remap));
8620 remap[n].infont = -1;
8621 mappos = 0;
8622 if ( sf->map!=NULL ) sf->map->remap = remap;
8623 } else if ( strmatch(tok,"Remap:")==0 ) {
8624 uint32 f, l; int p;
8625 gethex(sfd,&f);
8626 gethex(sfd,&l);
8627 getint(sfd,&p);
8628 if ( remap!=NULL && remap[mappos].infont!=-1 ) {
8629 remap[mappos].firstenc = f;
8630 remap[mappos].lastenc = l;
8631 remap[mappos].infont = p;
8632 mappos++;
8633 }
8634 } else if ( strmatch(tok,"CIDVersion:")==0 ) {
8635 real temp;
8636 getreal(sfd,&temp);
8637 sf->cidversion = temp;
8638 } else if ( strmatch(tok,"Grid")==0 ) {
8639 sf->grid.splines = SFDGetSplineSet(sfd,sf->grid.order2);
8640 } else if ( strmatch(tok,"ScriptLang:")==0 ) {
8641 int i,j,k;
8642 int imax, jmax, kmax;
8643 if ( sf->sfd_version==0 || sf->sfd_version>=2 ) {
8644 IError( "Script lang lists should not happen in version 2 sfd files." );
8645 SplineFontFree(sf);
8646 return NULL;
8647 }
8648 getint(sfd,&imax);
8649 ((SplineFont1 *) sf)->sli_cnt = imax;
8650 ((SplineFont1 *) sf)->script_lang = malloc((imax+1)*sizeof(struct script_record *));
8651 ((SplineFont1 *) sf)->script_lang[imax] = NULL;
8652 for ( i=0; i<imax; ++i ) {
8653 getint(sfd,&jmax);
8654 ((SplineFont1 *) sf)->script_lang[i] = malloc((jmax+1)*sizeof(struct script_record));
8655 ((SplineFont1 *) sf)->script_lang[i][jmax].script = 0;
8656 for ( j=0; j<jmax; ++j ) {
8657 ((SplineFont1 *) sf)->script_lang[i][j].script = gettag(sfd);
8658 getint(sfd,&kmax);
8659 ((SplineFont1 *) sf)->script_lang[i][j].langs = malloc((kmax+1)*sizeof(uint32));
8660 ((SplineFont1 *) sf)->script_lang[i][j].langs[kmax] = 0;
8661 for ( k=0; k<kmax; ++k ) {
8662 ((SplineFont1 *) sf)->script_lang[i][j].langs[k] = gettag(sfd);
8663 }
8664 }
8665 }
8666 } else if ( strmatch(tok,"TeXData:")==0 ) {
8667 int temp;
8668 getint(sfd,&temp);
8669 sf->texdata.type = temp;
8670 getint(sfd, &temp);
8671 if ( sf->design_size==0 ) {
8672 sf->design_size = (5*temp+(1<<18))>>19;
8673 }
8674 for ( i=0; i<22; ++i ) {
8675 int foo;
8676 getint(sfd,&foo);
8677 sf->texdata.params[i]=foo;
8678 }
8679 } else if ( strnmatch(tok,"AnchorClass",11)==0 ) {
8680 char *name;
8681 AnchorClass *lastan = NULL, *an;
8682 int old = strchr(tok,'2')==NULL;
8683 while ( (name=SFDReadUTF7Str(sfd))!=NULL ) {
8684 an = chunkalloc(old ? sizeof(AnchorClass1) : sizeof(AnchorClass));
8685 an->name = name;
8686 if ( old ) {
8687 getname(sfd,tok);
8688 if ( tok[0]=='0' && tok[1]=='\0' )
8689 ((AnchorClass1 *) an)->feature_tag = 0;
8690 else {
8691 if ( tok[1]=='\0' ) { tok[1]=' '; tok[2] = 0; }
8692 if ( tok[2]=='\0' ) { tok[2]=' '; tok[3] = 0; }
8693 if ( tok[3]=='\0' ) { tok[3]=' '; tok[4] = 0; }
8694 ((AnchorClass1 *) an)->feature_tag = (tok[0]<<24) | (tok[1]<<16) | (tok[2]<<8) | tok[3];
8695 }
8696 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
8697 ungetc(ch,sfd);
8698 if ( isdigit(ch)) {
8699 int temp;
8700 getint(sfd,&temp);
8701 ((AnchorClass1 *) an)->flags = temp;
8702 }
8703 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
8704 ungetc(ch,sfd);
8705 if ( isdigit(ch)) {
8706 int temp;
8707 getint(sfd,&temp);
8708 ((AnchorClass1 *) an)->script_lang_index = temp;
8709 } else
8710 ((AnchorClass1 *) an)->script_lang_index = 0xffff; /* Will be fixed up later */
8711 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
8712 ungetc(ch,sfd);
8713 if ( isdigit(ch)) {
8714 int temp;
8715 getint(sfd,&temp);
8716 ((AnchorClass1 *) an)->merge_with = temp;
8717 } else
8718 ((AnchorClass1 *) an)->merge_with = 0xffff; /* Will be fixed up later */
8719 } else {
8720 char *subtable_name = SFDReadUTF7Str(sfd);
8721 if ( subtable_name!=NULL) /* subtable is optional */
8722 an->subtable = SFFindLookupSubtableAndFreeName(sf,subtable_name);
8723 }
8724 while ( (ch=nlgetc(sfd))==' ' || ch=='\t' );
8725 ungetc(ch,sfd);
8726 if ( isdigit(ch) ) {
8727 /* Early versions of SfdFormat 2 had a number here */
8728 int temp;
8729 getint(sfd,&temp);
8730 an->type = temp;
8731 } else if ( old ) {
8732 if ( ((AnchorClass1 *) an)->feature_tag==CHR('c','u','r','s'))
8733 an->type = act_curs;
8734 else if ( ((AnchorClass1 *) an)->feature_tag==CHR('m','k','m','k'))
8735 an->type = act_mkmk;
8736 else
8737 an->type = act_mark;
8738 } else {
8739 an->type = act_mark;
8740 if( an->subtable && an->subtable->lookup )
8741 {
8742 switch ( an->subtable->lookup->lookup_type )
8743 {
8744 case gpos_cursive:
8745 an->type = act_curs;
8746 break;
8747 case gpos_mark2base:
8748 an->type = act_mark;
8749 break;
8750 case gpos_mark2ligature:
8751 an->type = act_mklg;
8752 break;
8753 case gpos_mark2mark:
8754 an->type = act_mkmk;
8755 break;
8756 default:
8757 an->type = act_mark;
8758 break;
8759 }
8760 }
8761 }
8762 if ( lastan==NULL )
8763 sf->anchor = an;
8764 else
8765 lastan->next = an;
8766 lastan = an;
8767 }
8768 } else if ( strncmp(tok,"MATH:",5)==0 ) {
8769 SFDParseMathItem(sfd,sf,tok);
8770 } else if ( strmatch(tok,"TableOrder:")==0 ) {
8771 int temp;
8772 struct table_ordering *ord;
8773 if ( sfdversion==0 || sfdversion>=2 ) {
8774 IError("Table ordering specified in version 2 sfd file.\n" );
8775 SplineFontFree(sf);
8776 return NULL;
8777 }
8778 ord = chunkalloc(sizeof(struct table_ordering));
8779 ord->table_tag = gettag(sfd);
8780 getint(sfd,&temp);
8781 ord->ordered_features = malloc((temp+1)*sizeof(uint32));
8782 ord->ordered_features[temp] = 0;
8783 for ( i=0; i<temp; ++i ) {
8784 while ( isspace((ch=nlgetc(sfd))) );
8785 if ( ch=='\'' ) {
8786 ungetc(ch,sfd);
8787 ord->ordered_features[i] = gettag(sfd);
8788 } else if ( ch=='<' ) {
8789 int f,s;
8790 fscanf(sfd,"%d,%d>", &f, &s );
8791 ord->ordered_features[i] = (f<<16)|s;
8792 }
8793 }
8794 if ( lastord==NULL )
8795 ((SplineFont1 *) sf)->orders = ord;
8796 else
8797 lastord->next = ord;
8798 lastord = ord;
8799 } else if ( strmatch(tok,"BeginPrivate:")==0 ) {
8800 SFDGetPrivate(sfd,sf);
8801 } else if ( strmatch(tok,"BeginSubrs:")==0 ) { /* leave in so we don't croak on old sfd files */
8802 SFDGetSubrs(sfd);
8803 } else if ( strmatch(tok,"PickledData:")==0 ) {
8804 if (sf->python_persistent != NULL) {
8805 #if defined(_NO_PYTHON)
8806 free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */
8807 #else
8808 PyFF_FreePythonPersistent(sf->python_persistent);
8809 #endif
8810 sf->python_persistent = NULL;
8811 }
8812 sf->python_persistent = SFDUnPickle(sfd, 0);
8813 sf->python_persistent_has_lists = 0;
8814 } else if ( strmatch(tok,"PickledDataWithLists:")==0 ) {
8815 if (sf->python_persistent != NULL) {
8816 #if defined(_NO_PYTHON)
8817 free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */
8818 #else
8819 PyFF_FreePythonPersistent(sf->python_persistent);
8820 #endif
8821 sf->python_persistent = NULL;
8822 }
8823 sf->python_persistent = SFDUnPickle(sfd, 1);
8824 sf->python_persistent_has_lists = 1;
8825 } else if ( strmatch(tok,"MMCounts:")==0 ) {
8826 MMSet *mm = sf->mm = chunkalloc(sizeof(MMSet));
8827 getint(sfd,&mm->instance_count);
8828 getint(sfd,&mm->axis_count);
8829 ch = nlgetc(sfd);
8830 if ( ch!=' ' )
8831 ungetc(ch,sfd);
8832 else { int temp;
8833 getint(sfd,&temp);
8834 mm->apple = temp;
8835 getint(sfd,&mm->named_instance_count);
8836 }
8837 mm->instances = calloc(mm->instance_count,sizeof(SplineFont *));
8838 mm->positions = malloc(mm->instance_count*mm->axis_count*sizeof(real));
8839 mm->defweights = malloc(mm->instance_count*sizeof(real));
8840 mm->axismaps = calloc(mm->axis_count,sizeof(struct axismap));
8841 if ( mm->named_instance_count!=0 )
8842 mm->named_instances = calloc(mm->named_instance_count,sizeof(struct named_instance));
8843 } else if ( strmatch(tok,"MMAxis:")==0 ) {
8844 MMSet *mm = sf->mm;
8845 if ( mm!=NULL ) {
8846 for ( i=0; i<mm->axis_count; ++i ) {
8847 getname(sfd,tok);
8848 mm->axes[i] = copy(tok);
8849 }
8850 }
8851 } else if ( strmatch(tok,"MMPositions:")==0 ) {
8852 MMSet *mm = sf->mm;
8853 if ( mm!=NULL ) {
8854 for ( i=0; i<mm->axis_count*mm->instance_count; ++i )
8855 getreal(sfd,&mm->positions[i]);
8856 }
8857 } else if ( strmatch(tok,"MMWeights:")==0 ) {
8858 MMSet *mm = sf->mm;
8859 if ( mm!=NULL ) {
8860 for ( i=0; i<mm->instance_count; ++i )
8861 getreal(sfd,&mm->defweights[i]);
8862 }
8863 } else if ( strmatch(tok,"MMAxisMap:")==0 ) {
8864 MMSet *mm = sf->mm;
8865 if ( mm!=NULL ) {
8866 int index, points;
8867 getint(sfd,&index); getint(sfd,&points);
8868 mm->axismaps[index].points = points;
8869 mm->axismaps[index].blends = malloc(points*sizeof(real));
8870 mm->axismaps[index].designs = malloc(points*sizeof(real));
8871 for ( i=0; i<points; ++i ) {
8872 getreal(sfd,&mm->axismaps[index].blends[i]);
8873 while ( (ch=nlgetc(sfd))!=EOF && isspace(ch));
8874 ungetc(ch,sfd);
8875 if ( (ch=nlgetc(sfd))!='=' )
8876 ungetc(ch,sfd);
8877 else if ( (ch=nlgetc(sfd))!='>' )
8878 ungetc(ch,sfd);
8879 getreal(sfd,&mm->axismaps[index].designs[i]);
8880 }
8881 lastaxismap = &mm->axismaps[index];
8882 lastnamedinstance = NULL;
8883 }
8884 } else if ( strmatch(tok,"MMNamedInstance:")==0 ) {
8885 MMSet *mm = sf->mm;
8886 if ( mm!=NULL ) {
8887 int index;
8888 getint(sfd,&index);
8889 mm->named_instances[index].coords = malloc(mm->axis_count*sizeof(real));
8890 for ( i=0; i<mm->axis_count; ++i )
8891 getreal(sfd,&mm->named_instances[index].coords[i]);
8892 lastnamedinstance = &mm->named_instances[index];
8893 lastaxismap = NULL;
8894 }
8895 } else if ( strmatch(tok,"MacName:")==0 ) {
8896 struct macname *names = SFDParseMacNames(sfd,tok);
8897 if ( lastaxismap!=NULL )
8898 lastaxismap->axisnames = names;
8899 else if ( lastnamedinstance !=NULL )
8900 lastnamedinstance->names = names;
8901 pushedbacktok = true;
8902 } else if ( strmatch(tok,"MMCDV:")==0 ) {
8903 MMSet *mm = sf->mm;
8904 if ( mm!=NULL )
8905 mm->cdv = SFDParseMMSubroutine(sfd);
8906 } else if ( strmatch(tok,"MMNDV:")==0 ) {
8907 MMSet *mm = sf->mm;
8908 if ( mm!=NULL )
8909 mm->ndv = SFDParseMMSubroutine(sfd);
8910 } else if ( strmatch(tok,"BeginMMFonts:")==0 ) {
8911 int cnt;
8912 getint(sfd,&cnt);
8913 getint(sfd,&realcnt);
8914 ff_progress_change_stages(cnt);
8915 ff_progress_change_total(realcnt);
8916 MMInferStuff(sf->mm);
8917 break;
8918 } else if ( strmatch(tok,"BeginSubFonts:")==0 ) {
8919 getint(sfd,&sf->subfontcnt);
8920 sf->subfonts = calloc(sf->subfontcnt,sizeof(SplineFont *));
8921 getint(sfd,&realcnt);
8922 sf->map = EncMap1to1(realcnt);
8923 ff_progress_change_stages(2);
8924 ff_progress_change_total(realcnt);
8925 break;
8926 } else if ( strmatch(tok,"BeginChars:")==0 ) {
8927 int charcnt;
8928 getint(sfd,&charcnt);
8929 if (charcnt<enc->char_cnt) {
8930 IError("SFD file specifies too few slots for its encoding.\n" );
8931 exit( 1 );
8932 }
8933 if ( getint(sfd,&realcnt)!=1 || realcnt==-1 )
8934 realcnt = charcnt;
8935 else
8936 ++realcnt; /* value saved is max glyph, not glyph cnt */
8937 ff_progress_change_total(realcnt);
8938 sf->glyphcnt = sf->glyphmax = realcnt;
8939 sf->glyphs = calloc(realcnt,sizeof(SplineChar *));
8940 if ( cidmaster!=NULL ) {
8941 sf->map = cidmaster->map;
8942 } else {
8943 sf->map = EncMapNew(charcnt,realcnt,enc);
8944 sf->map->remap = remap;
8945 }
8946 SFDSizeMap(sf->map,sf->glyphcnt,charcnt);
8947 break;
8948 #if HANYANG
8949 } else if ( strmatch(tok,"BeginCompositionRules")==0 ) {
8950 sf->rules = SFDReadCompositionRules(sfd);
8951 #endif
8952 } else {
8953 /* If we don't understand it, skip it */
8954 geteol(sfd,tok);
8955 }
8956 }
8957
8958 // Many downstream functions assume this isn't NULL (use strlen, etc.)
8959 if ( sf->fontname==NULL)
8960 sf->fontname = copy("");
8961
8962 if ( fromdir )
8963 sf = SFD_FigureDirType(sf,tok,dirname,enc,remap,had_layer_cnt);
8964 else if ( sf->subfontcnt!=0 ) {
8965 ff_progress_change_stages(2*sf->subfontcnt);
8966 for ( i=0; i<sf->subfontcnt; ++i ) {
8967 if ( i!=0 )
8968 ff_progress_next_stage();
8969 sf->subfonts[i] = SFD_GetFont(sfd,sf,tok,fromdir,dirname,sfdversion);
8970 }
8971 } else if ( sf->mm!=NULL ) {
8972 MMSet *mm = sf->mm;
8973 ff_progress_change_stages(2*(mm->instance_count+1));
8974 for ( i=0; i<mm->instance_count; ++i ) {
8975 if ( i!=0 )
8976 ff_progress_next_stage();
8977 mm->instances[i] = SFD_GetFont(sfd,NULL,tok,fromdir,dirname,sfdversion);
8978 EncMapFree(mm->instances[i]->map); mm->instances[i]->map=NULL;
8979 mm->instances[i]->mm = mm;
8980 }
8981 ff_progress_next_stage();
8982 mm->normal = SFD_GetFont(sfd,NULL,tok,fromdir,dirname,sfdversion);
8983 mm->normal->mm = mm;
8984 sf->mm = NULL;
8985 SplineFontFree(sf);
8986 sf = mm->normal;
8987 if ( sf->map->enc!=&custom ) {
8988 EncMap *map;
8989 MMMatchGlyphs(mm); /* sfd files from before the encoding change can have mismatched orig pos */
8990 map = EncMapFromEncoding(sf,sf->map->enc);
8991 EncMapFree(sf->map);
8992 sf->map = map;
8993 }
8994 } else {
8995 while ( SFDGetChar(sfd,sf,had_layer_cnt)!=NULL ) {
8996 ff_progress_next();
8997 }
8998 ff_progress_next_stage();
8999 }
9000 haddupenc = false;
9001 while ( getname(sfd,tok)==1 ) {
9002 if ( strcmp(tok,"EndSplineFont")==0 || strcmp(tok,"EndSubSplineFont")==0 )
9003 break;
9004 else if ( strcmp(tok,"BitmapFont:")==0 )
9005 SFDGetBitmapFont(sfd,sf,false,NULL);
9006 else if ( strmatch(tok,"DupEnc:")==0 ) {
9007 int enc, orig;
9008 haddupenc = true;
9009 if ( getint(sfd,&enc) && getint(sfd,&orig) && sf->map!=NULL ) {
9010 SFDSetEncMap(sf,orig,enc);
9011 }
9012 }
9013 }
9014 if ( sf->cidmaster==NULL )
9015 SFDFixupRefs(sf);
9016
9017 if ( !haddupenc )
9018 SFD_DoAltUnis(sf);
9019 else
9020 AltUniFigure(sf,sf->map,true);
9021 if ( sf->sfd_version<2 )
9022 SFD_AssignLookups((SplineFont1 *) sf);
9023 if ( !d.hadtimes )
9024 SFTimesFromFile(sf,sfd);
9025 // Make a blank encoding if there are no characters so as to avoid crashes later.
9026 if (sf->map == NULL) sf->map = EncMapNew(sf->glyphcnt,sf->glyphcnt,&custom);
9027
9028 SFDFixupUndoRefs(sf);
9029 return( sf );
9030 }
9031
SFTimesFromFile(SplineFont * sf,FILE * file)9032 void SFTimesFromFile(SplineFont *sf,FILE *file) {
9033 struct stat b;
9034 if ( fstat(fileno(file),&b)!=-1 ) {
9035 sf->modificationtime = GetST_MTime(b);
9036 sf->creationtime = GetST_MTime(b);
9037 }
9038 }
9039
SFDStartsCorrectly(FILE * sfd,char * tok)9040 static double SFDStartsCorrectly(FILE *sfd,char *tok) {
9041 real dval;
9042 int ch;
9043
9044 if ( getname(sfd,tok)!=1 )
9045 return( -1 );
9046 if ( strcmp(tok,"SplineFontDB:")!=0 )
9047 return( -1 );
9048 if ( getreal(sfd,&dval)!=1 )
9049 return( -1 );
9050 /* We don't yet generate version 4 of sfd. It will contain backslash */
9051 /* newline in the middle of very long lines. I've put in code to parse */
9052 /* this sequence, but I don't yet generate it. I want the parser to */
9053 /* perculate through to users before I introduce the new format so there */
9054 /* will be fewer complaints when it happens */
9055 // MIQ: getreal() can give some funky rounding errors it seems
9056 if ( dval!=0 && dval!=1 && dval!=2.0 && dval!=3.0
9057 && !(dval > 3.09 && dval <= 3.21)
9058 && dval!=4.0 )
9059 {
9060 LogError("Bad SFD Version number %.1f", dval );
9061 return( -1 );
9062 }
9063 ch = nlgetc(sfd); ungetc(ch,sfd);
9064 if ( ch!='\r' && ch!='\n' )
9065 return( -1 );
9066
9067 return( dval );
9068 }
9069
SFD_Read(char * filename,FILE * sfd,int fromdir)9070 static SplineFont *SFD_Read(char *filename,FILE *sfd, int fromdir) {
9071 SplineFont *sf=NULL;
9072 char tok[2000];
9073 double version;
9074
9075 if ( sfd==NULL ) {
9076 if ( fromdir ) {
9077 snprintf(tok,sizeof(tok),"%s/" FONT_PROPS, filename );
9078 sfd = fopen(tok,"r");
9079 } else
9080 sfd = fopen(filename,"r");
9081 }
9082 if ( sfd==NULL )
9083 return( NULL );
9084 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
9085 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
9086 ff_progress_change_stages(2);
9087 if ( (version = SFDStartsCorrectly(sfd,tok))!=-1 )
9088 sf = SFD_GetFont(sfd,NULL,tok,fromdir,filename,version);
9089 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
9090 if ( sf!=NULL ) {
9091 sf->filename = copy(filename);
9092 if ( sf->mm!=NULL ) {
9093 int i;
9094 for ( i=0; i<sf->mm->instance_count; ++i )
9095 sf->mm->instances[i]->filename = copy(filename);
9096 } else if ( !sf->onlybitmaps ) {
9097 /* Jonathyn Bet'nct points out that once you edit in an outline window, even */
9098 /* if by mistake, your onlybitmaps status is gone for good */
9099 /* Regenerate it if the font has no splines, refs, etc. */
9100 int i;
9101 SplineChar *sc;
9102 for ( i=sf->glyphcnt-1; i>=0; --i )
9103 if ( (sc = sf->glyphs[i])!=NULL &&
9104 (sc->layer_cnt!=2 ||
9105 sc->layers[ly_fore].splines!=NULL ||
9106 sc->layers[ly_fore].refs!=NULL ))
9107 break;
9108 if ( i==-1 )
9109 sf->onlybitmaps = true;
9110 }
9111 }
9112 fclose(sfd);
9113 return( sf );
9114 }
9115
SFDRead(char * filename)9116 SplineFont *SFDRead(char *filename) {
9117 return( SFD_Read(filename,NULL,false));
9118 }
9119
_SFDRead(char * filename,FILE * sfd)9120 SplineFont *_SFDRead(char *filename,FILE *sfd) {
9121 return( SFD_Read(filename,sfd,false));
9122 }
9123
SFDirRead(char * filename)9124 SplineFont *SFDirRead(char *filename) {
9125 return( SFD_Read(filename,NULL,true));
9126 }
9127
SFDReadOneChar(SplineFont * cur_sf,const char * name)9128 SplineChar *SFDReadOneChar(SplineFont *cur_sf,const char *name) {
9129 FILE *sfd;
9130 SplineChar *sc=NULL;
9131 char oldloc[25], tok[2000];
9132 uint32 pos;
9133 SplineFont sf;
9134 LayerInfo layers[2];
9135 double version;
9136 int had_layer_cnt=false;
9137 int chars_seen = false;
9138
9139 if ( cur_sf->save_to_dir ) {
9140 snprintf(tok,sizeof(tok),"%s/" FONT_PROPS,cur_sf->filename);
9141 sfd = fopen(tok,"r");
9142 } else
9143 sfd = fopen(cur_sf->filename,"r");
9144 if ( sfd==NULL )
9145 return( NULL );
9146 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
9147 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
9148
9149 memset(&sf,0,sizeof(sf));
9150 memset(&layers,0,sizeof(layers));
9151 sf.layer_cnt = 2;
9152 sf.layers = layers;
9153 sf.ascent = 800; sf.descent = 200;
9154 if ( cur_sf->cidmaster ) cur_sf = cur_sf->cidmaster;
9155 if ( (version = SFDStartsCorrectly(sfd,tok))>=2 ) {
9156 sf.sfd_version = version;
9157 sf.gpos_lookups = cur_sf->gpos_lookups;
9158 sf.gsub_lookups = cur_sf->gsub_lookups;
9159 sf.anchor = cur_sf->anchor;
9160 pos = ftell(sfd);
9161 while ( getname(sfd,tok)!=-1 ) {
9162 if ( strcmp(tok,"StartChar:")==0 ) {
9163 if ( getname(sfd,tok)==1 && strcmp(tok,name)==0 ) {
9164 fseek(sfd,pos,SEEK_SET);
9165 sc = SFDGetChar(sfd,&sf,had_layer_cnt);
9166 break;
9167 }
9168 } else if ( strmatch(tok,"BeginChars:")==0 ) {
9169 chars_seen = true;
9170 } else if ( chars_seen ) {
9171 /* Don't try to look for things in the file header any more */
9172 /* The "Layer" keyword has a different meaning in this context */
9173 } else if ( strmatch(tok,"Order2:")==0 ) {
9174 int order2;
9175 getint(sfd,&order2);
9176 sf.grid.order2 = order2;
9177 sf.layers[ly_back].order2 = order2;
9178 sf.layers[ly_fore].order2 = order2;
9179 } else if ( strmatch(tok,"LayerCount:")==0 ) {
9180 had_layer_cnt = true;
9181 getint(sfd,&sf.layer_cnt);
9182 if ( sf.layer_cnt>2 ) {
9183 sf.layers = calloc(sf.layer_cnt,sizeof(LayerInfo));
9184 }
9185 } else if ( strmatch(tok,"Layer:")==0 ) {
9186 int layer, o2;
9187 getint(sfd,&layer);
9188 getint(sfd,&o2);
9189 if ( layer<sf.layer_cnt )
9190 sf.layers[layer].order2 = o2;
9191 free( SFDReadUTF7Str(sfd));
9192 } else if ( strmatch(tok,"MultiLayer:")==0 ) {
9193 int ml;
9194 getint(sfd,&ml);
9195 sf.multilayer = ml;
9196 } else if ( strmatch(tok,"StrokedFont:")==0 ) {
9197 int stk;
9198 getint(sfd,&stk);
9199 sf.strokedfont = stk;
9200 } else if ( strmatch(tok,"Ascent:")==0 ) {
9201 getint(sfd,&sf.ascent);
9202 } else if ( strmatch(tok,"Descent:")==0 ) {
9203 getint(sfd,&sf.descent);
9204 } else if ( strmatch(tok,"InvalidEm:")==0 ) {
9205 getint(sfd,&sf.invalidem);
9206 }
9207 pos = ftell(sfd);
9208 }
9209 }
9210 fclose(sfd);
9211 if ( cur_sf->save_to_dir ) {
9212 if ( sc!=NULL ) IError("Read a glyph from font.props");
9213 /* Doesn't work for CID keyed, nor for mm */
9214 snprintf(tok,sizeof(tok),"%s/%s" GLYPH_EXT,cur_sf->filename,name);
9215 sfd = fopen(tok,"r");
9216 if ( sfd!=NULL ) {
9217 sc = SFDGetChar(sfd,&sf,had_layer_cnt);
9218 fclose(sfd);
9219 }
9220 }
9221
9222 if ( sf.layers!=layers )
9223 free(sf.layers);
9224 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
9225 return( sc );
9226 }
9227
ModSF(FILE * asfd,SplineFont * sf)9228 static int ModSF(FILE *asfd,SplineFont *sf) {
9229 Encoding *newmap;
9230 int cnt;
9231 int multilayer=0;
9232 char tok[200];
9233 int i,k;
9234 SplineChar *sc;
9235 SplineFont *ssf;
9236 SplineFont temp;
9237 int layercnt;
9238
9239 memset(&temp,0,sizeof(temp));
9240 temp.layers = sf->layers;
9241 temp.layer_cnt = sf->layer_cnt;
9242 temp.layers[ly_back].order2 = sf->layers[ly_back].order2;
9243 temp.layers[ly_fore].order2 = sf->layers[ly_fore].order2;
9244 temp.ascent = sf->ascent; temp.descent = sf->descent;
9245 temp.multilayer = sf->multilayer;
9246 temp.gpos_lookups = sf->gpos_lookups;
9247 temp.gsub_lookups = sf->gsub_lookups;
9248 temp.anchor = sf->anchor;
9249 temp.sfd_version = 2;
9250
9251 if ( getname(asfd,tok)!=1 || strcmp(tok,"Encoding:")!=0 )
9252 return(false);
9253 newmap = SFDGetEncoding(asfd,tok);
9254 if ( getname(asfd,tok)!=1 )
9255 return( false );
9256 if ( strcmp(tok,"UnicodeInterp:")==0 ) {
9257 sf->uni_interp = SFDGetUniInterp(asfd,tok,sf);
9258 if ( getname(asfd,tok)!=1 )
9259 return( false );
9260 }
9261 if ( sf->map!=NULL && sf->map->enc!=newmap ) {
9262 EncMap *map = EncMapFromEncoding(sf,newmap);
9263 EncMapFree(sf->map);
9264 sf->map = map;
9265 }
9266 temp.map = sf->map;
9267 if ( strcmp(tok,"LayerCount:")==0 ) {
9268 getint(asfd,&layercnt);
9269 if ( layercnt>sf->layer_cnt ) {
9270 sf->layers = realloc(sf->layers,layercnt*sizeof(LayerInfo));
9271 memset(sf->layers+sf->layer_cnt,0,(layercnt-sf->layer_cnt)*sizeof(LayerInfo));
9272 }
9273 sf->layer_cnt = layercnt;
9274 if ( getname(asfd,tok)!=1 )
9275 return( false );
9276 }
9277 while ( strcmp(tok,"Layer:")==0 ) {
9278 int layer, o2;
9279 getint(asfd,&layer);
9280 getint(asfd,&o2);
9281 if ( layer<sf->layer_cnt ) {
9282 sf->layers[layer].order2 = o2;
9283 if (sf->layers[layer].name)
9284 free(sf->layers[layer].name);
9285 sf->layers[layer].name = SFDReadUTF7Str(asfd);
9286 }
9287 if ( getname(asfd,tok)!=1 )
9288 return( false );
9289 }
9290 if ( strcmp(tok,"MultiLayer:")==0 ) {
9291 getint(asfd,&multilayer);
9292 if ( getname(asfd,tok)!=1 )
9293 return( false );
9294 }
9295 if ( multilayer!=sf->multilayer ) {
9296 if ( !multilayer )
9297 SFSplinesFromLayers(sf,false);
9298 sf->multilayer = multilayer;
9299 /* SFLayerChange(sf);*/ /* Shouldn't have any open windows, should not be needed */
9300 }
9301 if ( strcmp(tok,"BeginChars:")!=0 )
9302 return(false);
9303 SFRemoveDependencies(sf);
9304
9305 getint(asfd,&cnt);
9306 if ( cnt>sf->glyphcnt ) {
9307 sf->glyphs = realloc(sf->glyphs,cnt*sizeof(SplineChar *));
9308 for ( i=sf->glyphcnt; i<cnt; ++i )
9309 sf->glyphs[i] = NULL;
9310 sf->glyphcnt = sf->glyphmax = cnt;
9311 }
9312 while ( (sc = SFDGetChar(asfd,&temp,true))!=NULL ) {
9313 ssf = sf;
9314 for ( k=0; k<sf->subfontcnt; ++k ) {
9315 if ( sc->orig_pos<sf->subfonts[k]->glyphcnt ) {
9316 ssf = sf->subfonts[k];
9317 if ( SCWorthOutputting(ssf->glyphs[sc->orig_pos]))
9318 break;
9319 }
9320 }
9321 if ( sc->orig_pos<ssf->glyphcnt ) {
9322 if ( ssf->glyphs[sc->orig_pos]!=NULL )
9323 SplineCharFree(ssf->glyphs[sc->orig_pos]);
9324 ssf->glyphs[sc->orig_pos] = sc;
9325 sc->parent = ssf;
9326 sc->changed = true;
9327 }
9328 }
9329 sf->changed = true;
9330 SFDFixupRefs(sf);
9331 return(true);
9332 }
9333
SlurpRecovery(FILE * asfd,char * tok,int sizetok)9334 static SplineFont *SlurpRecovery(FILE *asfd,char *tok,int sizetok) {
9335 char *pt; int ch;
9336 SplineFont *sf;
9337
9338 ch=nlgetc(asfd);
9339 ungetc(ch,asfd);
9340 if ( ch=='B' ) {
9341 if ( getname(asfd,tok)!=1 )
9342 return(NULL);
9343 if ( strcmp(tok,"Base:")!=0 )
9344 return(NULL);
9345 while ( isspace(ch=nlgetc(asfd)) && ch!=EOF && ch!='\n' );
9346 for ( pt=tok; ch!=EOF && ch!='\n'; ch = nlgetc(asfd) )
9347 if ( pt<tok+sizetok-2 )
9348 *pt++ = ch;
9349 *pt = '\0';
9350 sf = LoadSplineFont(tok,0);
9351 } else {
9352 sf = SplineFontNew();
9353 sf->onlybitmaps = false;
9354 strcpy(tok,"<New File>");
9355 }
9356 if ( sf==NULL )
9357 return( NULL );
9358
9359 if ( !ModSF(asfd,sf)) {
9360 SplineFontFree(sf);
9361 return( NULL );
9362 }
9363 return( sf );
9364 }
9365
9366 /**
9367 * Asks the user whether or not to recover, skip or delete an autosaved file.
9368 * If requested by the user, this function will attempt to delete the file.
9369 * @param [in] filename The path to the autosaved file.
9370 * @param [in,out] state The current state.
9371 * state&1: Recover all. state&2: Forget all.
9372 * @param [out] asfd Location to store the file pointer to the autosaved file.
9373 * @return true iff the file is to be recovered. If true, asfd will hold the
9374 * corresponding file pointer, which must be closed by the caller. If
9375 * false, asfd will hold NULL.
9376 */
ask_about_file(char * filename,int * state,FILE ** asfd)9377 static int ask_about_file(char *filename, int *state, FILE **asfd) {
9378 int ret;
9379 char *buts[6];
9380 char buffer[800], *pt;
9381
9382 if ((*asfd = fopen(filename, "r")) == NULL) {
9383 return false;
9384 } else if (*state&1) { //Recover all
9385 return true;
9386 } else if (*state&2) { //Forget all
9387 fclose(*asfd);
9388 *asfd = NULL;
9389 unlink(filename);
9390 return false;
9391 }
9392
9393 fgets(buffer,sizeof(buffer),*asfd);
9394 rewind(*asfd);
9395 if (strncmp(buffer,"Base: ",6) != 0) {
9396 strcpy(buffer+6, "<New File>");
9397 }
9398 pt = buffer+6;
9399 if (strlen(buffer+6) > 70) {
9400 pt = strrchr(buffer+6,'/');
9401 if (pt == NULL)
9402 pt = buffer+6;
9403 }
9404
9405 buts[0] = _("Yes"); buts[1] = _("Yes to _All");
9406 buts[2] = _("_Skip for now");
9407 buts[3] = _("Forget _to All"); buts[4] = _("_Forget about it");
9408 buts[5] = NULL;
9409 ret = ff_ask(_("Recover old edit"),(const char **) buts,0,3,_("You appear to have an old editing session on %s.\nWould you like to recover it?"), pt);
9410 switch (ret) {
9411 case 1: //Recover all
9412 *state = 1;
9413 break;
9414 case 2: //Skip one
9415 fclose(*asfd);
9416 *asfd = NULL;
9417 return false;
9418 case 3: //Forget all
9419 *state = 2;
9420 /* Fall through */
9421 case 4: //Forget one
9422 fclose(*asfd);
9423 *asfd = NULL;
9424 unlink(filename);
9425 return false;
9426 default: //Recover one
9427 break;
9428 }
9429 return true;
9430 }
9431
SFRecoverFile(char * autosavename,int inquire,int * state)9432 SplineFont *SFRecoverFile(char *autosavename,int inquire,int *state) {
9433 FILE *asfd;
9434 SplineFont *ret;
9435 char tok[1025];
9436
9437 if (!inquire) {
9438 *state = 1; //Default to recover all
9439 }
9440 if (!ask_about_file(autosavename, state, &asfd)) {
9441 return( NULL );
9442 }
9443 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
9444 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
9445 ret = SlurpRecovery(asfd,tok,sizeof(tok));
9446 if ( ret==NULL ) {
9447 const char *buts[3];
9448 buts[0] = "_Forget It"; buts[1] = "_Try Again"; buts[2] = NULL;
9449 if ( ff_ask(_("Recovery Failed"),(const char **) buts,0,1,_("Automagic recovery of changes to %.80s failed.\nShould FontForge try again to recover next time you start it?"),tok)==0 )
9450 unlink(autosavename);
9451 }
9452 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
9453 fclose(asfd);
9454 if ( ret )
9455 ret->autosavename = copy(autosavename);
9456 return( ret );
9457 }
9458
SFAutoSave(SplineFont * sf,EncMap * map)9459 void SFAutoSave(SplineFont *sf,EncMap *map) {
9460 int i, k, max;
9461 FILE *asfd;
9462 SplineFont *ssf;
9463
9464 if ( no_windowing_ui ) /* No autosaves when just scripting */
9465 return;
9466
9467 if ( sf->cidmaster!=NULL ) sf=sf->cidmaster;
9468 asfd = fopen(sf->autosavename,"w");
9469 if ( asfd==NULL )
9470 return;
9471
9472 max = sf->glyphcnt;
9473 for ( i=0; i<sf->subfontcnt; ++i )
9474 if ( sf->subfonts[i]->glyphcnt>max ) max = sf->subfonts[i]->glyphcnt;
9475
9476 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
9477 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
9478 if ( !sf->new && sf->origname!=NULL ) /* might be a new file */
9479 fprintf( asfd, "Base: %s%s\n", sf->origname,
9480 sf->compression==0?"":compressors[sf->compression-1].ext );
9481 fprintf( asfd, "Encoding: %s\n", map->enc->enc_name );
9482 fprintf( asfd, "UnicodeInterp: %s\n", unicode_interp_names[sf->uni_interp]);
9483 fprintf( asfd, "LayerCount: %d\n", sf->layer_cnt );
9484 for ( i=0; i<sf->layer_cnt; ++i ) {
9485 fprintf( asfd, "Layer: %d %d ", i, sf->layers[i].order2 );
9486 SFDDumpUTF7Str(asfd,sf->layers[i].name);
9487 putc('\n',asfd);
9488 }
9489 if ( sf->multilayer )
9490 fprintf( asfd, "MultiLayer: %d\n", sf->multilayer );
9491 fprintf( asfd, "BeginChars: %d\n", max );
9492 for ( i=0; i<max; ++i ) {
9493 ssf = sf;
9494 for ( k=0; k<sf->subfontcnt; ++k ) {
9495 if ( i<sf->subfonts[k]->glyphcnt ) {
9496 ssf = sf->subfonts[k];
9497 if ( SCWorthOutputting(ssf->glyphs[i]))
9498 break;
9499 }
9500 }
9501 if ( ssf->glyphs[i]!=NULL && ssf->glyphs[i]->changed )
9502 SFDDumpChar( asfd,ssf->glyphs[i],map,NULL,false,1);
9503 }
9504 fprintf( asfd, "EndChars\n" );
9505 fprintf( asfd, "EndSplineFont\n" );
9506 fclose(asfd);
9507 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
9508 sf->changed_since_autosave = false;
9509 }
9510
SFClearAutoSave(SplineFont * sf)9511 void SFClearAutoSave(SplineFont *sf) {
9512 int i;
9513 SplineFont *ssf;
9514
9515 if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
9516 sf->changed_since_autosave = false;
9517 for ( i=0; i<sf->subfontcnt; ++i ) {
9518 ssf = sf->subfonts[i];
9519 ssf->changed_since_autosave = false;
9520 if ( ssf->autosavename!=NULL ) {
9521 unlink( ssf->autosavename );
9522 free( ssf->autosavename );
9523 ssf->autosavename = NULL;
9524 }
9525 }
9526 if ( sf->autosavename==NULL )
9527 return;
9528 unlink(sf->autosavename);
9529 free(sf->autosavename);
9530 sf->autosavename = NULL;
9531 }
9532
NamesReadSFD(char * filename)9533 char **NamesReadSFD(char *filename) {
9534 FILE *sfd = fopen(filename,"r");
9535 char tok[2000];
9536 char **ret = NULL;
9537 int eof;
9538
9539 if ( sfd==NULL )
9540 return( NULL );
9541 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
9542 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
9543 if ( SFDStartsCorrectly(sfd,tok)!=-1 ) {
9544 while ( !feof(sfd)) {
9545 if ( (eof = getname(sfd,tok))!=1 ) {
9546 if ( eof==-1 )
9547 break;
9548 geteol(sfd,tok);
9549 continue;
9550 }
9551 if ( strmatch(tok,"FontName:")==0 ) {
9552 getname(sfd,tok);
9553 ret = malloc(2*sizeof(char*));
9554 ret[0] = copy(tok);
9555 ret[1] = NULL;
9556 break;
9557 }
9558 }
9559 }
9560 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
9561 fclose(sfd);
9562 return( ret );
9563 }
9564