1 /* Copyright (C) 2000-2008 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "pfaedit.h"
28 #include <chardata.h>
29 #include <utype.h>
30 #include <ustring.h>
31 #include <math.h>
32 #include <locale.h>
33 #include <stdlib.h>
34 #include "ttf.h"
35 
getAppleClassTable(FILE * ttf,int classdef_offset,int cnt,int sub,int div,struct ttfinfo * info)36 static uint16 *getAppleClassTable(FILE *ttf, int classdef_offset, int cnt, int sub, int div, struct ttfinfo *info) {
37     uint16 *class = gcalloc(cnt,sizeof(uint16));
38     int first, i, n;
39     /* Apple stores its class tables as containing offsets. I find it hard to */
40     /*  think that way and convert them to indeces (by subtracting off a base */
41     /*  offset and dividing by the item's size) before doing anything else */
42 
43     fseek(ttf,classdef_offset,SEEK_SET);
44     first = getushort(ttf);
45     n = getushort(ttf);
46     if ( first+n-1>=cnt ) {
47 	LogError( _("Bad Apple Kern Class\n") );
48 	info->bad_gx = true;
49     }
50     for ( i=0; i<n && i+first<cnt; ++i )
51 	class[first+i] = (getushort(ttf)-sub)/div;
52 return( class );
53 }
54 
ClassToNames(struct ttfinfo * info,int class_cnt,uint16 * class,int glyph_cnt)55 static char **ClassToNames(struct ttfinfo *info,int class_cnt,uint16 *class,int glyph_cnt) {
56     char **ret = galloc(class_cnt*sizeof(char *));
57     int *lens = gcalloc(class_cnt,sizeof(int));
58     int i;
59 
60     ret[0] = NULL;
61     for ( i=0 ; i<glyph_cnt; ++i ) if ( class[i]!=0 && info->chars[i]!=NULL && class[i]<class_cnt )
62 	lens[class[i]] += strlen(info->chars[i]->name)+1;
63     for ( i=1; i<class_cnt ; ++i )
64 	ret[i] = galloc(lens[i]+1);
65     memset(lens,0,class_cnt*sizeof(int));
66     for ( i=0 ; i<glyph_cnt; ++i ) if ( class[i]!=0 && info->chars[i]!=NULL ) {
67 	if ( class[i]<class_cnt ) {
68 	    strcpy(ret[class[i]]+lens[class[i]], info->chars[i]->name );
69 	    lens[class[i]] += strlen(info->chars[i]->name)+1;
70 	    ret[class[i]][lens[class[i]]-1] = ' ';
71 	} else {
72 	    LogError( _("Class index out of range %d (must be <%d)\n"),class[i], class_cnt );
73 	    info->bad_ot = true;
74 	}
75     }
76     for ( i=1; i<class_cnt ; ++i )
77 	if ( lens[i]==0 )
78 	    ret[i][0] = '\0';
79 	else
80 	    ret[i][lens[i]-1] = '\0';
81     free(lens);
82 return( ret );
83 }
84 
CoverageMinusClasses(uint16 * coverageglyphs,uint16 * classed,struct ttfinfo * info)85 static char *CoverageMinusClasses(uint16 *coverageglyphs,uint16 *classed,
86 	struct ttfinfo *info ) {
87     int i, j, len;
88     uint8 *glyphs = gcalloc(info->glyph_cnt,1);
89     char *ret;
90 
91     for ( i=0; coverageglyphs[i]!=0xffff; ++i )
92 	glyphs[coverageglyphs[i]] = 1;
93     for ( i=0; i<info->glyph_cnt; ++i )
94 	if ( classed[i]!=0 )
95 	    glyphs[i] = 0;
96     for ( i=0; i<info->glyph_cnt; ++i )
97 	if ( glyphs[i]!=0 )
98     break;
99     /* coverage table matches glyphs in classes. No need for special treatment*/
100     if ( i==info->glyph_cnt ) {
101 	free(glyphs);
102 return( NULL );
103     }
104     /* Otherwise we need to generate a class string of glyph names in the coverage */
105     /*  table but not in any class. These become the glyphs in class 0 */
106     ret = NULL;
107     for ( j=0; j<2; ++j ) {
108 	len = 0;
109 	for ( i=0; i<info->glyph_cnt; ++i ) {
110 	    if ( glyphs[i]!=0 ) {
111 		if ( j ) {
112 		    strcpy( ret+len, info->chars[i]->name );
113 		    strcat( ret+len, " ");
114 		}
115 		len += strlen(info->chars[i]->name)+1;
116 	    }
117 	}
118 	if ( j==0 )
119 	    ret = galloc(len+1);
120 	else
121 	    ret[len-1] = '\0';
122     }
123     free(glyphs);
124 return( ret );
125 }
126 
ClassFindCnt(uint16 * class,int tot)127 static int ClassFindCnt(uint16 *class,int tot) {
128     int i, max=0;
129 
130     for ( i=0; i<tot; ++i )
131 	if ( class[i]>max ) max = class[i];
132 return( max+1 );
133 }
134 
cmpuint16(const void * u1,const void * u2)135 static int cmpuint16(const void *u1, const void *u2) {
136 return( ((int) *((const uint16 *) u1)) - ((int) *((const uint16 *) u2)) );
137 }
138 
GlyphsToNames(struct ttfinfo * info,uint16 * glyphs,int make_uniq)139 static char *GlyphsToNames(struct ttfinfo *info,uint16 *glyphs,int make_uniq) {
140     int i, j, len, off;
141     char *ret, *pt;
142 
143     if ( glyphs==NULL )
144 return( copy(""));
145 
146     /* Adobe produces coverage tables containing duplicate glyphs in */
147     /*  GaramondPremrPro.otf. We want unique glyphs, so enforce that */
148     if ( make_uniq ) {
149 	for ( i=0 ; glyphs[i]!=0xffff; ++i );
150 	qsort(glyphs,i,sizeof(uint16),cmpuint16);
151 	for ( i=0; glyphs[i]!=0xffff; ++i ) {
152 	    if ( glyphs[i+1]==glyphs[i] ) {
153 		for ( j=i+1; glyphs[j]==glyphs[i]; ++j );
154 		off = j-i -1;
155 		for ( j=i+1; ; ++j ) {
156 		    glyphs[j] = glyphs[j+off];
157 		    if ( glyphs[j]==0xffff )
158 		break;
159 		}
160 	    }
161 	}
162     }
163 
164     for ( i=len=0 ; glyphs[i]!=0xffff; ++i )
165 	if ( info->chars[glyphs[i]]!=NULL )
166 	    len += strlen(info->chars[glyphs[i]]->name)+1;
167     ret = pt = galloc(len+1); *pt = '\0';
168     for ( i=0 ; glyphs[i]!=0xffff; ++i ) if ( info->chars[glyphs[i]]!=NULL ) {
169 	strcpy(pt,info->chars[glyphs[i]]->name);
170 	pt += strlen(pt);
171 	*pt++ = ' ';
172     }
173     if ( pt>ret ) pt[-1] = '\0';
174 return( ret );
175 }
176 
177 struct scripts {
178     uint32 offset;
179     uint32 tag;
180     int langcnt;		/* the default language is included as a */
181     struct language {		/* normal entry with lang tag 'dflt' */
182 	uint32 tag;
183 	uint32 offset;
184 	uint16 req;		/* required feature index. 0xffff for null */
185 	int fcnt;
186 	uint16 *features;
187     } *languages;
188 };
189 
190 struct feature {
191     uint32 offset;
192     uint32 tag;
193     int lcnt;
194     uint16 *lookups;
195 };
196 
197 struct lookup {
198     uint16 type;
199     uint16 flags;
200     /* uint16 lookup; */	/* ???? can't imagine what this is*/
201     uint32 offset;
202     int subtabcnt;
203     int32 *subtab_offsets;
204     OTLookup *otlookup;
205 };
206 
getCoverageTable(FILE * ttf,int coverage_offset,struct ttfinfo * info)207 static uint16 *getCoverageTable(FILE *ttf, int coverage_offset, struct ttfinfo *info) {
208     int format, cnt, i,j, rcnt;
209     uint16 *glyphs=NULL;
210     int start, end, ind, max;
211 
212     fseek(ttf,coverage_offset,SEEK_SET);
213     format = getushort(ttf);
214     if ( format==1 ) {
215 	cnt = getushort(ttf);
216 	glyphs = galloc((cnt+1)*sizeof(uint16));
217 	if ( ftell(ttf)+2*cnt > info->g_bounds ) {
218 	    LogError( _("coverage table extends beyond end of table\n") );
219 	    info->bad_ot = true;
220 	    if ( ftell(ttf)>info->g_bounds )
221 return( NULL );
222 	    cnt = (info->g_bounds-ftell(ttf))/2;
223 	}
224 	for ( i=0; i<cnt; ++i ) {
225 	    if ( cnt&0xffff0000 ) {
226 		LogError( _("Bad count.\n"));
227 		info->bad_ot = true;
228 	    }
229 	    glyphs[i] = getushort(ttf);
230 	    if ( feof(ttf) ) {
231 		LogError( _("End of file found in coverage table.\n") );
232 		info->bad_ot = true;
233 		free(glyphs);
234 return( NULL );
235 	    }
236 	    if ( glyphs[i]>=info->glyph_cnt ) {
237 		LogError( _("Bad coverage table. Glyph %d out of range [0,%d)\n"), glyphs[i], info->glyph_cnt );
238 		info->bad_ot = true;
239 		glyphs[i] = 0;
240 	    }
241 	}
242     } else if ( format==2 ) {
243 	glyphs = gcalloc((max=256),sizeof(uint16));
244 	rcnt = getushort(ttf); cnt = 0;
245 	if ( ftell(ttf)+6*rcnt > info->g_bounds ) {
246 	    LogError( _("coverage table extends beyond end of table\n") );
247 	    info->bad_ot = true;
248 	    rcnt = (info->g_bounds-ftell(ttf))/6;
249 	}
250 
251 	for ( i=0; i<rcnt; ++i ) {
252 	    start = getushort(ttf);
253 	    end = getushort(ttf);
254 	    ind = getushort(ttf);
255 	    if ( feof(ttf) ) {
256 		LogError( _("End of file found in coverage table.\n") );
257 		info->bad_ot = true;
258 		free(glyphs);
259 return( NULL );
260 	    }
261 	    if ( start>end || end>=info->glyph_cnt ) {
262 		LogError( _("Bad coverage table. Glyph range %d-%d out of range [0,%d)\n"), start, end, info->glyph_cnt );
263 		info->bad_ot = true;
264 		start = end = 0;
265 	    }
266 	    if ( ind+end-start+2 >= max ) {
267 		int oldmax = max;
268 		max = ind+end-start+2;
269 		glyphs = grealloc(glyphs,max*sizeof(uint16));
270 		memset(glyphs+oldmax,0,(max-oldmax)*sizeof(uint16));
271 	    }
272 	    for ( j=start; j<=end; ++j ) {
273 		glyphs[j-start+ind] = j;
274 		if ( j>=info->glyph_cnt )
275 		    glyphs[j-start+ind] = 0;
276 	    }
277 	    if ( ind+end-start+1>cnt )
278 		cnt = ind+end-start+1;
279 	}
280     } else {
281 	LogError( _("Bad format for coverage table %d\n"), format );
282 	info->bad_ot = true;
283 return( NULL );
284     }
285     glyphs[cnt] = 0xffff;
286 
287 return( glyphs );
288 }
289 
290 struct valuerecord {
291     int16 xplacement, yplacement;
292     int16 xadvance, yadvance;
293     uint16 offXplaceDev, offYplaceDev;
294     uint16 offXadvanceDev, offYadvanceDev;
295 };
296 
getClassDefTable(FILE * ttf,int classdef_offset,struct ttfinfo * info)297 static uint16 *getClassDefTable(FILE *ttf, int classdef_offset, struct ttfinfo *info) {
298     int format, i, j;
299     uint16 start, glyphcnt, rangecnt, end, class;
300     uint16 *glist=NULL;
301     int warned = false;
302     int cnt = info->glyph_cnt;
303     uint32 g_bounds = info->g_bounds;
304 
305     fseek(ttf, classdef_offset, SEEK_SET);
306     glist = gcalloc(cnt,sizeof(uint16));	/* Class 0 is default */
307     format = getushort(ttf);
308     if ( format==1 ) {
309 	start = getushort(ttf);
310 	glyphcnt = getushort(ttf);
311 	if ( start+(int) glyphcnt>cnt ) {
312 	    LogError( _("Bad class def table. start=%d cnt=%d, max glyph=%d\n"), start, glyphcnt, cnt );
313 	    info->bad_ot = true;
314 	    glyphcnt = cnt-start;
315 	} else if ( ftell(ttf)+2*glyphcnt > g_bounds ) {
316 	    LogError( _("Class definition sub-table extends beyond end of table\n") );
317 	    info->bad_ot = true;
318         if (g_bounds<ftell(ttf))
319             glyphcnt = 0;
320 	    else
321             glyphcnt = (g_bounds-ftell(ttf))/2;
322 	}
323 	for ( i=0; i<glyphcnt; ++i )
324 	    glist[start+i] = getushort(ttf);
325     } else if ( format==2 ) {
326 	rangecnt = getushort(ttf);
327 	if ( ftell(ttf)+6*rangecnt > g_bounds ) {
328 	    LogError( _("Class definition sub-table extends beyond end of table\n") );
329 	    info->bad_ot = true;
330 	    rangecnt = (g_bounds-ftell(ttf))/6;
331 	}
332 	for ( i=0; i<rangecnt; ++i ) {
333 	    start = getushort(ttf);
334 	    end = getushort(ttf);
335 	    if ( start>end || end>=cnt ) {
336 		LogError( _("Bad class def table. Glyph range %d-%d out of range [0,%d)\n"), start, end, cnt );
337 		info->bad_ot = true;
338 	    }
339 	    class = getushort(ttf);
340 	    for ( j=start; j<=end; ++j ) if ( j<cnt )
341 		glist[j] = class;
342 	}
343     } else {
344 	LogError( _("Unknown class table format: %d\n"), format );
345 	info->bad_ot = true;
346     }
347 
348     /* Do another validity test */
349     for ( i=0; i<cnt; ++i ) {
350 	if ( glist[i]>=cnt+1 ) {
351 	    if ( !warned ) {
352 		LogError( _("Nonsensical class assigned to a glyph-- class=%d is too big. Glyph=%d\n"),
353 			glist[i], i );
354 		info->bad_ot = true;
355 		warned = true;
356 	    }
357 	    glist[i] = 0;
358 	}
359     }
360 
361 return glist;
362 }
363 
readvaluerecord(struct valuerecord * vr,int vf,FILE * ttf)364 static void readvaluerecord(struct valuerecord *vr,int vf,FILE *ttf) {
365     memset(vr,'\0',sizeof(struct valuerecord));
366     if ( vf&1 )
367 	vr->xplacement = getushort(ttf);
368     if ( vf&2 )
369 	vr->yplacement = getushort(ttf);
370     if ( vf&4 )
371 	vr->xadvance = getushort(ttf);
372     if ( vf&8 )
373 	vr->yadvance = getushort(ttf);
374     if ( vf&0x10 )
375 	vr->offXplaceDev = getushort(ttf);
376     if ( vf&0x20 )
377 	vr->offYplaceDev = getushort(ttf);
378     if ( vf&0x40 )
379 	vr->offXadvanceDev = getushort(ttf);
380     if ( vf&0x80 )
381 	vr->offYadvanceDev = getushort(ttf);
382 }
383 
384 #ifdef FONTFORGE_CONFIG_DEVICETABLES
ReadDeviceTable(FILE * ttf,DeviceTable * adjust,uint32 devtab,struct ttfinfo * info)385 static void ReadDeviceTable(FILE *ttf,DeviceTable *adjust,uint32 devtab,
386 	struct ttfinfo *info) {
387     long here;
388     int pack;
389     int w,b,i,c;
390 
391     if ( devtab==0 )
392 return;
393     here = ftell(ttf);
394     fseek(ttf,devtab,SEEK_SET);
395     adjust->first_pixel_size = getushort(ttf);
396     adjust->last_pixel_size  = getushort(ttf);
397     pack = getushort(ttf);
398     if ( adjust->first_pixel_size>adjust->last_pixel_size || pack==0 || pack>3 ) {
399 	LogError(_("Bad device table\n" ));
400 	info->bad_ot = true;
401 	adjust->first_pixel_size = adjust->last_pixel_size = 0;
402     } else {
403 	c = adjust->last_pixel_size-adjust->first_pixel_size+1;
404 	adjust->corrections = galloc(c);
405 	if ( pack==1 ) {
406 	    for ( i=0; i<c; i+=8 ) {
407 		w = getushort(ttf);
408 		for ( b=0; b<8 && i+b<c; ++b )
409 		    adjust->corrections[i+b] = ((int16) ((w<<(b*2))&0xc000))>>14;
410 	    }
411 	} else if ( pack==2 ) {
412 	    for ( i=0; i<c; i+=4 ) {
413 		w = getushort(ttf);
414 		for ( b=0; b<4 && i+b<c; ++b )
415 		    adjust->corrections[i+b] = ((int16) ((w<<(b*4))&0xf000))>>12;
416 	    }
417 	} else {
418 	    for ( i=0; i<c; ++i )
419 		adjust->corrections[i] = (int8) getc(ttf);
420 	}
421     }
422     fseek(ttf,here,SEEK_SET);
423 }
424 
readValDevTab(FILE * ttf,struct valuerecord * vr,uint32 base,struct ttfinfo * info)425 static ValDevTab *readValDevTab(FILE *ttf,struct valuerecord *vr,uint32 base,
426 	struct ttfinfo *info) {
427     ValDevTab *ret;
428 
429     if ( vr->offXplaceDev==0 && vr->offYplaceDev==0 &&
430 	    vr->offXadvanceDev==0 && vr->offYadvanceDev==0 )
431 return( NULL );
432     ret = chunkalloc(sizeof(ValDevTab));
433     if ( vr->offXplaceDev!=0 )
434 	ReadDeviceTable(ttf,&ret->xadjust,base + vr->offXplaceDev,info);
435     if ( vr->offYplaceDev!=0 )
436 	ReadDeviceTable(ttf,&ret->yadjust,base + vr->offYplaceDev,info);
437     if ( vr->offXadvanceDev!=0 )
438 	ReadDeviceTable(ttf,&ret->xadv,base + vr->offXadvanceDev,info);
439     if ( vr->offYadvanceDev!=0 )
440 	ReadDeviceTable(ttf,&ret->yadv,base + vr->offYadvanceDev,info);
441 return( ret );
442 }
443 #endif
444 
addPairPos(struct ttfinfo * info,int glyph1,int glyph2,struct lookup * l,struct lookup_subtable * subtable,struct valuerecord * vr1,struct valuerecord * vr2,uint32 base,FILE * ttf)445 static void addPairPos(struct ttfinfo *info, int glyph1, int glyph2,
446 	struct lookup *l, struct lookup_subtable *subtable, struct valuerecord *vr1,struct valuerecord *vr2,
447 	uint32 base,FILE *ttf) {
448     (void)ttf; /* for -Wall */
449     (void)l; /* for -Wall */
450     (void)base; /* for -Wall */
451     if ( glyph1<info->glyph_cnt && glyph2<info->glyph_cnt ) {
452 	PST *pos = chunkalloc(sizeof(PST));
453 	pos->type = pst_pair;
454 	pos->subtable = subtable;
455 	pos->next = info->chars[glyph1]->possub;
456 	info->chars[glyph1]->possub = pos;
457 	pos->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
458 	pos->u.pair.paired = copy(info->chars[glyph2]->name);
459 	pos->u.pair.vr[0].xoff = vr1->xplacement;
460 	pos->u.pair.vr[0].yoff = vr1->yplacement;
461 	pos->u.pair.vr[0].h_adv_off = vr1->xadvance;
462 	pos->u.pair.vr[0].v_adv_off = vr1->yadvance;
463 	pos->u.pair.vr[1].xoff = vr2->xplacement;
464 	pos->u.pair.vr[1].yoff = vr2->yplacement;
465 	pos->u.pair.vr[1].h_adv_off = vr2->xadvance;
466 	pos->u.pair.vr[1].v_adv_off = vr2->yadvance;
467 #ifdef FONTFORGE_CONFIG_DEVICETABLES
468 	pos->u.pair.vr[0].adjust = readValDevTab(ttf,vr1,base,info);
469 	pos->u.pair.vr[1].adjust = readValDevTab(ttf,vr2,base,info);
470 #endif
471     } else {
472 	LogError( _("Bad pair position: glyphs %d & %d should have been < %d\n"),
473 		glyph1, glyph2, info->glyph_cnt );
474 	info->bad_ot = true;
475     }
476 }
477 
addKernPair(struct ttfinfo * info,int glyph1,int glyph2,int16 offset,uint32 devtab,struct lookup * l,struct lookup_subtable * subtable,int isv,FILE * ttf)478 static int addKernPair(struct ttfinfo *info, int glyph1, int glyph2,
479 	int16 offset, uint32 devtab, struct lookup *l, struct lookup_subtable *subtable,int isv,
480 	FILE *ttf) {
481     KernPair *kp;
482     (void)ttf; /* for -Wall */
483     (void)l; /* for -Wall */
484     (void)devtab; /* for -Wall */
485     if ( glyph1<info->glyph_cnt && glyph2<info->glyph_cnt &&
486 	    info->chars[glyph1]!=NULL && info->chars[glyph2]!=NULL ) {
487 	for ( kp=isv ? info->chars[glyph1]->vkerns : info->chars[glyph1]->kerns;
488 		kp!=NULL; kp=kp->next ) {
489 	    if ( kp->sc == info->chars[glyph2] )
490 	break;
491 	}
492 	if ( kp==NULL ) {
493 	    kp = chunkalloc(sizeof(KernPair));
494 	    kp->sc = info->chars[glyph2];
495 	    kp->off = offset;
496 	    kp->subtable = subtable;
497 #ifdef FONTFORGE_CONFIG_DEVICETABLES
498 	    if ( devtab!=0 ) {
499 		kp->adjust = chunkalloc(sizeof(DeviceTable));
500 		ReadDeviceTable(ttf,kp->adjust,devtab,info);
501 	    }
502 #endif
503 	    if ( isv ) {
504 		kp->next = info->chars[glyph1]->vkerns;
505 		info->chars[glyph1]->vkerns = kp;
506 	    } else {
507 		kp->next = info->chars[glyph1]->kerns;
508 		info->chars[glyph1]->kerns = kp;
509 	    }
510 	} else if ( kp->subtable!=subtable )
511 return( true );
512     } else if ( glyph1>=info->glyph_cnt || glyph2>=info->glyph_cnt ) {
513 	/* Might be NULL in a ttc file where we omit glyphs */
514 	LogError( _("Bad kern pair: glyphs %d & %d should have been < %d\n"),
515 		glyph1, glyph2, info->glyph_cnt );
516 	info->bad_ot = true;
517     }
518 return( false );
519 }
520 
gposKernSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable)521 static void gposKernSubTable(FILE *ttf, int stoffset, struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable) {
522     int coverage, cnt, i, j, pair_cnt, vf1, vf2, glyph2;
523     int cd1, cd2, c1_cnt, c2_cnt;
524     uint16 format;
525     uint16 *ps_offsets;
526     uint16 *glyphs, *class1, *class2;
527     struct valuerecord vr1, vr2;
528     long foffset;
529     KernClass *kc;
530     int isv, r2l;
531 
532     format=getushort(ttf);
533     if ( format!=1 && format!=2 )	/* Unknown subtable format */
534 return;
535     coverage = getushort(ttf);
536     vf1 = getushort(ttf);
537     vf2 = getushort(ttf);
538     r2l = 0;
539 
540     /* Accept forms both with and without device tables */
541     if ( (vf1==0x0008 || vf1==0x0088) && vf2==0x0000 )
542 	isv = 1;		/* Top to bottom */
543     else if ( vf1==0x0000 && (vf2==0x0004 || vf2==0x0044) && (l->flags&pst_r2l)) {
544 	isv = 0;		/* Right to left */
545 	r2l = 1;
546     } else if ( (vf1==0x0004 || vf1==0x0044) && vf2==0x0000 && !(l->flags&pst_r2l) )
547 	isv = 0;		/* Left to right */
548     else
549 	isv = 2;		/* Can't optimize, store all 8 settings */
550     if ( format==1 ) {
551 	subtable->per_glyph_pst_or_kern = true;
552 	cnt = getushort(ttf);
553 	ps_offsets = galloc(cnt*sizeof(uint16));
554 	for ( i=0; i<cnt; ++i )
555 	    ps_offsets[i]=getushort(ttf);
556 	glyphs = getCoverageTable(ttf,stoffset+coverage,info);
557 	if ( glyphs==NULL )
558 return;
559 	for ( i=0; i<cnt; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
560 	    fseek(ttf,stoffset+ps_offsets[i],SEEK_SET);
561 	    pair_cnt = getushort(ttf);
562 	    for ( j=0; j<pair_cnt; ++j ) {
563 		glyph2 = getushort(ttf);
564 		readvaluerecord(&vr1,vf1,ttf);
565 		readvaluerecord(&vr2,vf2,ttf);
566 		if ( isv==2 )
567 		    addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2, stoffset,ttf);
568 		else if ( isv ) {
569 		    if ( addKernPair(info, glyphs[i], glyph2, vr1.yadvance,
570 			    vr1.offYadvanceDev==0?0:stoffset+vr1.offYadvanceDev,
571 			    l,subtable,isv,ttf))
572 			addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2, stoffset,ttf);
573 			/* If we've already got kern data for this pair of */
574 			/*  glyphs, then we can't make it be a true KernPair */
575 			/*  but we can save the info as a pst_pair */
576 		} else if ( r2l ) {	/* R2L */
577 		    if ( addKernPair(info, glyphs[i], glyph2, vr2.xadvance,
578 			    vr2.offXadvanceDev==0?0:stoffset+vr2.offXadvanceDev,
579 			    l,subtable,isv,ttf))
580 			addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2,stoffset,ttf);
581 		} else {
582 		    if ( addKernPair(info, glyphs[i], glyph2, vr1.xadvance,
583 			    vr1.offXadvanceDev==0?0:stoffset+vr1.offXadvanceDev,
584 			    l,subtable,isv,ttf))
585 			addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2,stoffset,ttf);
586 		}
587 	    }
588 	}
589 	free(ps_offsets); free(glyphs);
590     } else if ( format==2 ) {	/* Class-based kerning */
591 	cd1 = getushort(ttf);
592 	cd2 = getushort(ttf);
593 	foffset = ftell(ttf);
594 	class1 = getClassDefTable(ttf, stoffset+cd1, info);
595 	class2 = getClassDefTable(ttf, stoffset+cd2, info);
596 	glyphs = getCoverageTable(ttf,stoffset+coverage,info);
597 	fseek(ttf, foffset, SEEK_SET);	/* come back */
598 	c1_cnt = getushort(ttf);
599 	c2_cnt = getushort(ttf);
600 	if ( isv!=2 ) {
601 	    if ( isv ) {
602 		if ( info->vkhead==NULL )
603 		    info->vkhead = kc = chunkalloc(sizeof(KernClass));
604 		else
605 		    kc = info->vklast->next = chunkalloc(sizeof(KernClass));
606 		info->vklast = kc;
607 	    } else {
608 		if ( info->khead==NULL )
609 		    info->khead = kc = chunkalloc(sizeof(KernClass));
610 		else
611 		    kc = info->klast->next = chunkalloc(sizeof(KernClass));
612 		info->klast = kc;
613 	    }
614 	    subtable->vertical_kerning = isv;
615 	    subtable->kc = kc;
616 	    kc->first_cnt = c1_cnt; kc->second_cnt = c2_cnt;
617 	    kc->subtable = subtable;
618 	    kc->offsets = galloc(c1_cnt*c2_cnt*sizeof(int16));
619 #ifdef FONTFORGE_CONFIG_DEVICETABLES
620 	    kc->adjusts = gcalloc(c1_cnt*c2_cnt,sizeof(DeviceTable));
621 #endif
622 	    kc->firsts = ClassToNames(info,c1_cnt,class1,info->glyph_cnt);
623 	    kc->seconds = ClassToNames(info,c2_cnt,class2,info->glyph_cnt);
624 	    /* Now if the coverage table contains entries which are not in */
625 	    /*  the list of first classes, then those glyphs are the real */
626 	    /*  values for kc->firsts[0] */
627 	    kc->firsts[0] = CoverageMinusClasses(glyphs,class1,info);
628 	    for ( i=0; i<c1_cnt; ++i) {
629 		for ( j=0; j<c2_cnt; ++j) {
630 		    readvaluerecord(&vr1,vf1,ttf);
631 		    readvaluerecord(&vr2,vf2,ttf);
632 		    if ( isv )
633 			kc->offsets[i*c2_cnt+j] = vr1.yadvance;
634 		    else if ( r2l )
635 			kc->offsets[i*c2_cnt+j] = vr2.xadvance;
636 		    else
637 			kc->offsets[i*c2_cnt+j] = vr1.xadvance;
638 #ifdef FONTFORGE_CONFIG_DEVICETABLES
639 		    if ( isv ) {
640 			if ( vr1.offYadvanceDev!=0 )
641 			    ReadDeviceTable(ttf,&kc->adjusts[i*c2_cnt+j],stoffset+vr1.offYadvanceDev,info);
642 		    } else if ( r2l ) {
643 			if ( vr2.offXadvanceDev!=0 )
644 			    ReadDeviceTable(ttf,&kc->adjusts[i*c2_cnt+j],stoffset+vr2.offXadvanceDev,info);
645 		    } else {
646 			if ( vr1.offXadvanceDev!=0 )
647 			    ReadDeviceTable(ttf,&kc->adjusts[i*c2_cnt+j],stoffset+vr1.offXadvanceDev,info);
648 		    }
649 #endif
650 		}
651 	    }
652 	} else {	/* This happens when we have a feature which is neither 'kern' nor 'vkrn' we don't know what to do with it so we make it into kern pairs */
653 	    int k,m;
654 	    subtable->per_glyph_pst_or_kern = true;
655 	    for ( i=0; i<c1_cnt; ++i) {
656 		for ( j=0; j<c2_cnt; ++j) {
657 		    readvaluerecord(&vr1,vf1,ttf);
658 		    readvaluerecord(&vr2,vf2,ttf);
659 		    if ( vr1.xadvance!=0 || vr1.xplacement!=0 || vr1.yadvance!=0 || vr1.yplacement!=0 ||
660 			    vr2.xadvance!=0 || vr2.xplacement!=0 || vr2.yadvance!=0 || vr2.yplacement!=0 )
661 			for ( k=0; k<info->glyph_cnt; ++k )
662 			    if ( class1[k]==i )
663 				for ( m=0; m<info->glyph_cnt; ++m )
664 				    if ( class2[m]==j )
665 					addPairPos(info, k,m,l,subtable,&vr1,&vr2,stoffset,ttf);
666 		}
667 	    }
668 	}
669 	free(class1); free(class2);
670 	free(glyphs);
671     }
672 }
673 
readAnchorPoint(FILE * ttf,uint32 base,AnchorClass * class,enum anchor_type type,AnchorPoint * last,struct ttfinfo * info)674 static AnchorPoint *readAnchorPoint(FILE *ttf,uint32 base,AnchorClass *class,
675 	enum anchor_type type,AnchorPoint *last, struct ttfinfo *info) {
676     AnchorPoint *ap;
677     int format;
678     (void)info; /* for -Wall */
679     fseek(ttf,base,SEEK_SET);
680 
681     ap = chunkalloc(sizeof(AnchorPoint));
682     ap->anchor = class;
683     /* All anchor types have the same initial 3 entries, format */
684     /*  x,y pos. format 2 contains a truetype positioning point, and */
685     /*  format==3 may also have device tables */
686     format = getushort(ttf);
687     ap->me.x = (int16) getushort(ttf);
688     ap->me.y = (int16) getushort(ttf);
689     ap->type = type;
690     if ( format==2 ) {
691 	ap->ttf_pt_index = getushort(ttf);
692 	ap->has_ttf_pt = true;
693     }
694 #ifdef FONTFORGE_CONFIG_DEVICETABLES
695     else if ( format==3 ) {
696 	int devoff;
697 	devoff = getushort(ttf);
698 	if ( devoff!=0 )
699 	    ReadDeviceTable(ttf,&ap->xadjust,base+devoff,info);
700 	devoff = getushort(ttf);
701 	if ( devoff!=0 )
702 	    ReadDeviceTable(ttf,&ap->yadjust,base+devoff,info);
703     }
704 #endif
705     ap->next = last;
706 return( ap );
707 }
708 
gposCursiveSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable)709 static void gposCursiveSubTable(FILE *ttf, int stoffset, struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable) {
710     int coverage, cnt, format, i;
711     struct ee_offsets { int entry, exit; } *offsets;
712     uint16 *glyphs;
713     AnchorClass *class;
714     SplineChar *sc;
715     char buf[50];
716     (void)l; /* for -Wall */
717     format=getushort(ttf);
718     if ( format!=1 )	/* Unknown subtable format */
719 return;
720     coverage = getushort(ttf);
721     cnt = getushort(ttf);
722     if ( cnt==0 )
723 return;
724     offsets = galloc(cnt*sizeof(struct ee_offsets));
725     for ( i=0; i<cnt; ++i ) {
726 	offsets[i].entry = getushort(ttf);
727 	offsets[i].exit  = getushort(ttf);
728     }
729     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
730 
731     class = chunkalloc(sizeof(AnchorClass));
732     snprintf(buf,sizeof(buf),_("Cursive-%d"),
733 	    info->anchor_class_cnt++ );
734     class->name = copy(buf);
735     subtable->anchor_classes = true;
736     class->subtable = subtable;
737     class->type = act_curs;
738     if ( info->ahead==NULL )
739 	info->ahead = class;
740     else
741 	info->alast->next = class;
742     info->alast = class;
743 
744     for ( i=0; i<cnt; ++i ) {
745 	sc = info->chars[glyphs[i]];
746 	if ( offsets[i].entry!=0 ) {
747 	    sc->anchor = readAnchorPoint(ttf,stoffset+offsets[i].entry,class,
748 		    at_centry,sc->anchor,info);
749 	}
750 	if ( offsets[i].exit!=0 ) {
751 	    sc->anchor = readAnchorPoint(ttf,stoffset+offsets[i].exit,class,
752 		    at_cexit,sc->anchor,info);
753 	}
754     }
755     free(offsets);
756     free(glyphs);
757 }
758 
MarkGlyphsProcessMarks(FILE * ttf,int markoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,uint16 * markglyphs,int classcnt)759 static AnchorClass **MarkGlyphsProcessMarks(FILE *ttf,int markoffset,
760 	struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable,uint16 *markglyphs,
761 	int classcnt) {
762     AnchorClass **classes = gcalloc(classcnt,sizeof(AnchorClass *)), *ac;
763     char buf[50];
764     int i, cnt;
765     struct mr { uint16 class, offset; } *at_offsets;
766     SplineChar *sc;
767 
768     for ( i=0; i<classcnt; ++i ) {
769 	snprintf(buf,sizeof(buf),_("Anchor-%d"),
770 		info->anchor_class_cnt+i );
771 	classes[i] = ac = chunkalloc(sizeof(AnchorClass));
772 	ac->name = copy(buf);
773 	subtable->anchor_classes = true;
774 	ac->subtable = subtable;
775 	/*ac->merge_with = info->anchor_merge_cnt+1;*/
776 	ac->type = l->otlookup->lookup_type==gpos_mark2mark ? act_mkmk : act_mark;
777 	    /* I don't distinguish between mark to base and mark to lig */
778 	if ( info->ahead==NULL )
779 	    info->ahead = ac;
780 	else
781 	    info->alast->next = ac;
782 	info->alast = ac;
783     }
784 
785     fseek(ttf,markoffset,SEEK_SET);
786     cnt = getushort(ttf);
787     if ( feof(ttf) ) {
788 	LogError( _("Bad mark table.\n") );
789 	info->bad_ot = true;
790 return( NULL );
791     }
792     at_offsets = galloc(cnt*sizeof(struct mr));
793     for ( i=0; i<cnt; ++i ) {
794 	at_offsets[i].class = getushort(ttf);
795 	at_offsets[i].offset = getushort(ttf);
796 	if ( at_offsets[i].class>=classcnt ) {
797 	    at_offsets[i].class = 0;
798 	    if ( markglyphs[i]>=info->glyph_cnt )
799 		LogError( _("Class out of bounds in GPOS mark sub-table\n") );
800 	    else
801 		LogError( _("Class out of bounds in GPOS mark sub-table for mark %.30s\n"), info->chars[markglyphs[i]]->name);
802 	    info->bad_ot = true;
803 	}
804     }
805     for ( i=0; i<cnt; ++i ) {
806 	if ( markglyphs[i]>=info->glyph_cnt )
807     continue;
808 	sc = info->chars[markglyphs[i]];
809 	if ( sc==NULL || at_offsets[i].offset==0 )
810     continue;
811 	sc->anchor = readAnchorPoint(ttf,markoffset+at_offsets[i].offset,
812 		classes[at_offsets[i].class],at_mark,sc->anchor,info);
813     }
814     free(at_offsets);
815 return( classes );
816 }
817 
MarkGlyphsProcessBases(FILE * ttf,int baseoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,uint16 * baseglyphs,int classcnt,AnchorClass ** classes,enum anchor_type at)818 static void MarkGlyphsProcessBases(FILE *ttf,int baseoffset,
819 	struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable,uint16 *baseglyphs,int classcnt,
820 	AnchorClass **classes,enum anchor_type at) {
821     int basecnt,i, j, ibase;
822     uint16 *offsets;
823     SplineChar *sc;
824     (void)subtable; /* for -Wall */
825     (void)l; /* for -Wall */
826     fseek(ttf,baseoffset,SEEK_SET);
827     basecnt = getushort(ttf);
828     if ( feof(ttf) ) {
829 	LogError( _("Bad base table.\n") );
830 	info->bad_ot = true;
831 return;
832     }
833     offsets = galloc(basecnt*classcnt*sizeof(uint16));
834     for ( i=0; i<basecnt*classcnt; ++i )
835 	offsets[i] = getushort(ttf);
836     for ( i=ibase=0; i<basecnt; ++i, ibase+= classcnt ) {
837 	if ( baseglyphs[i]>=info->glyph_cnt )
838     continue;
839 	sc = info->chars[baseglyphs[i]];
840 	if ( sc==NULL )
841     continue;
842 	for ( j=0; j<classcnt; ++j ) if ( offsets[ibase+j]!=0 ) {
843 	    sc->anchor = readAnchorPoint(ttf,baseoffset+offsets[ibase+j],
844 		    classes[j], at,sc->anchor,info);
845 	}
846     }
847     free(offsets);
848 }
849 
MarkGlyphsProcessLigs(FILE * ttf,int baseoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,uint16 * baseglyphs,int classcnt,AnchorClass ** classes)850 static void MarkGlyphsProcessLigs(FILE *ttf,int baseoffset,
851 	struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable,uint16 *baseglyphs,int classcnt,
852 	AnchorClass **classes) {
853     int basecnt,compcnt, i, j, k, kbase;
854     uint16 *loffsets, *aoffsets;
855     SplineChar *sc;
856     (void)subtable; /* for -Wall */
857     (void)l; /* for -Wall */
858     fseek(ttf,baseoffset,SEEK_SET);
859     basecnt = getushort(ttf);
860     if ( feof(ttf) ) {
861 	LogError( _("Bad ligature base table.\n") );
862 	info->bad_ot = true;
863 return;
864     }
865     loffsets = galloc(basecnt*sizeof(uint16));
866     for ( i=0; i<basecnt; ++i )
867 	loffsets[i] = getushort(ttf);
868     for ( i=0; i<basecnt; ++i ) {
869 	sc = info->chars[baseglyphs[i]];
870 	if ( baseglyphs[i]>=info->glyph_cnt || sc==NULL )
871     continue;
872 	fseek(ttf,baseoffset+loffsets[i],SEEK_SET);
873 	compcnt = getushort(ttf);
874 	if ( feof(ttf)) {
875 	    LogError(_("Bad ligature anchor count.\n"));
876 	    info->bad_ot = true;
877     continue;
878 	}
879 	aoffsets = galloc(compcnt*classcnt*sizeof(uint16));
880 	for ( k=0; k<compcnt*classcnt; ++k )
881 	    aoffsets[k] = getushort(ttf);
882 	for ( k=kbase=0; k<compcnt; ++k, kbase+=classcnt ) {
883 	    for ( j=0; j<classcnt; ++j ) if ( aoffsets[kbase+j]!=0 ) {
884 		sc->anchor = readAnchorPoint(ttf,baseoffset+loffsets[i]+aoffsets[kbase+j],
885 			classes[j], at_baselig,sc->anchor,info);
886 		sc->anchor->lig_index = k;
887 	    }
888 	}
889 	free(aoffsets);
890     }
891     free(loffsets);
892 }
893 
gposMarkSubTable(FILE * ttf,uint32 stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable)894 static void gposMarkSubTable(FILE *ttf, uint32 stoffset,
895 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable) {
896     int markcoverage, basecoverage, classcnt, markoffset, baseoffset;
897     uint16 *markglyphs, *baseglyphs;
898     AnchorClass **classes;
899 
900 	/* The header for the three different mark tables is the same */
901     /* Type = */ getushort(ttf);
902     markcoverage = getushort(ttf);
903     basecoverage = getushort(ttf);
904     classcnt = getushort(ttf);
905     markoffset = getushort(ttf);
906     baseoffset = getushort(ttf);
907     markglyphs = getCoverageTable(ttf,stoffset+markcoverage,info);
908     baseglyphs = getCoverageTable(ttf,stoffset+basecoverage,info);
909     if ( baseglyphs==NULL || markglyphs==NULL ) {
910 	free(baseglyphs); free(markglyphs);
911 return;
912     }
913 	/* as is the (first) mark table */
914     classes = MarkGlyphsProcessMarks(ttf,stoffset+markoffset,
915 	    info,l,subtable,markglyphs,classcnt);
916     if ( classes==NULL )
917 return;
918     switch ( l->otlookup->lookup_type ) {
919       case gpos_mark2base:
920       case gpos_mark2mark:
921 	  MarkGlyphsProcessBases(ttf,stoffset+baseoffset,
922 	    info,l,subtable,baseglyphs,classcnt,classes,
923 	    l->otlookup->lookup_type==gpos_mark2base?at_basechar:at_basemark);
924       break;
925       case gpos_mark2ligature:
926 	  MarkGlyphsProcessLigs(ttf,stoffset+baseoffset,
927 	    info,l,subtable,baseglyphs,classcnt,classes);
928       break;
929       default:
930       break;
931     }
932     info->anchor_class_cnt += classcnt;
933     ++ info->anchor_merge_cnt;
934     free(markglyphs); free(baseglyphs);
935     free(classes);
936 }
937 
gposSimplePos(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable)938 static void gposSimplePos(FILE *ttf, int stoffset, struct ttfinfo *info,
939 	struct lookup *l, struct lookup_subtable *subtable) {
940     int coverage, cnt, i, vf;
941     uint16 format;
942     uint16 *glyphs;
943     struct valuerecord *vr=NULL, _vr, *which;
944     (void)l; /* for -Wall */
945     format=getushort(ttf);
946     if ( format!=1 && format!=2 )	/* Unknown subtable format */
947 return;
948     coverage = getushort(ttf);
949     vf = getushort(ttf);
950 #ifdef FONTFORGE_CONFIG_DEVICETABLES
951     if ( vf==0 )
952 return;
953 #else
954     if ( (vf&0xf)==0 )	/* Not interested in things whose data just live in device tables */
955 return;
956 #endif
957     if ( format==1 ) {
958 	memset(&_vr,0,sizeof(_vr));
959 	readvaluerecord(&_vr,vf,ttf);
960     } else {
961 	cnt = getushort(ttf);
962 	vr = gcalloc(cnt,sizeof(struct valuerecord));
963 	for ( i=0; i<cnt; ++i )
964 	    readvaluerecord(&vr[i],vf,ttf);
965     }
966     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
967     if ( glyphs==NULL ) {
968 	free(vr);
969 return;
970     }
971     for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
972 	PST *pos = chunkalloc(sizeof(PST));
973 	pos->type = pst_position;
974 	pos->subtable = subtable;
975 	pos->next = info->chars[glyphs[i]]->possub;
976 	info->chars[glyphs[i]]->possub = pos;
977 	which = format==1 ? &_vr : &vr[i];
978 	pos->u.pos.xoff = which->xplacement;
979 	pos->u.pos.yoff = which->yplacement;
980 	pos->u.pos.h_adv_off = which->xadvance;
981 	pos->u.pos.v_adv_off = which->yadvance;
982 #ifdef FONTFORGE_CONFIG_DEVICETABLES
983 	pos->u.pos.adjust = readValDevTab(ttf,which,stoffset,info);
984 #endif
985     }
986     subtable->per_glyph_pst_or_kern = true;
987     free(vr);
988     free(glyphs);
989 }
990 
ProcessSubLookups(FILE * ttf,struct ttfinfo * info,int gpos,struct lookup * alllooks,struct seqlookup * sl)991 static void ProcessSubLookups(FILE *ttf,struct ttfinfo *info,int gpos,
992 	struct lookup *alllooks,struct seqlookup *sl) {
993     int i;
994     (void)ttf; /* for -Wall */
995     i = (intpt) sl->lookup;
996     if ( i<0 || i>=info->lookup_cnt ) {
997 	LogError( _("Attempt to reference lookup %d (within a contextual lookup), but there are\n only %d lookups in %s\n"),
998 		i, info->lookup_cnt, gpos ? "'GPOS'" : "'GSUB'" );
999 	info->bad_ot = true;
1000 	sl->lookup = NULL;
1001 return;
1002     }
1003     sl->lookup = alllooks[i].otlookup;
1004 }
1005 
g___ContextSubTable1(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks,int gpos)1006 static void g___ContextSubTable1(FILE *ttf, int stoffset,
1007 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1008 	struct lookup *alllooks, int gpos) {
1009     int i, j, k, rcnt, cnt;
1010     uint16 coverage;
1011     uint16 *glyphs;
1012     struct subrule {
1013 	uint32 offset;
1014 	int gcnt;
1015 	int scnt;
1016 	uint16 *glyphs;
1017 	struct seqlookup *sl;
1018     };
1019     struct rule {
1020 	uint32 offsets;
1021 	int scnt;
1022 	struct subrule *subrules;
1023     } *rules;
1024     FPST *fpst;
1025     struct fpst_rule *rule;
1026     int warned = false, warned2 = false;
1027     (void)l; /* for -Wall */
1028     coverage = getushort(ttf);
1029     rcnt = getushort(ttf);		/* glyph count in coverage table */
1030     rules = galloc(rcnt*sizeof(struct rule));
1031     for ( i=0; i<rcnt; ++i )
1032 	rules[i].offsets = getushort(ttf)+stoffset;
1033     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1034     cnt = 0;
1035     for ( i=0; i<rcnt; ++i ) {
1036 	fseek(ttf,rules[i].offsets,SEEK_SET);
1037 	rules[i].scnt = getushort(ttf);
1038 	cnt += rules[i].scnt;
1039 	rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1040 	for ( j=0; j<rules[i].scnt; ++j )
1041 	    rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1042 	for ( j=0; j<rules[i].scnt; ++j ) {
1043 	    fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1044 	    rules[i].subrules[j].gcnt = getushort(ttf);
1045 	    rules[i].subrules[j].scnt = getushort(ttf);
1046 	    rules[i].subrules[j].glyphs = galloc((rules[i].subrules[j].gcnt+1)*sizeof(uint16));
1047 	    rules[i].subrules[j].glyphs[0] = glyphs[i];
1048 	    for ( k=1; k<rules[i].subrules[j].gcnt; ++k ) {
1049 		rules[i].subrules[j].glyphs[k] = getushort(ttf);
1050 		if ( rules[i].subrules[j].glyphs[k]>=info->glyph_cnt ) {
1051 		    if ( !warned )
1052 			LogError( _("Bad contextual or chaining sub table. Glyph %d out of range [0,%d)\n"),
1053 				 rules[i].subrules[j].glyphs[k], info->glyph_cnt );
1054 		    info->bad_ot = true;
1055 		    warned = true;
1056 		    rules[i].subrules[j].glyphs[k] = 0;
1057 		 }
1058 	    }
1059 	    rules[i].subrules[j].glyphs[k] = 0xffff;
1060 	    rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1061 	    for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1062 		rules[i].subrules[j].sl[k].seq = getushort(ttf);
1063 		if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].gcnt+1 )
1064 		    if ( !warned2 ) {
1065 			LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1066 				rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].gcnt );
1067 			info->bad_ot = true;
1068 			warned2 = true;
1069 		    }
1070 		rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1071 	    }
1072 	}
1073     }
1074 
1075     if ( justinuse==git_justinuse ) {
1076 	/* Nothing to do. This lookup doesn't really reference any glyphs */
1077 	/*  any lookups it invokes will be processed on their own */
1078     } else {
1079 	fpst = chunkalloc(sizeof(FPST));
1080 	fpst->type = gpos ? pst_contextpos : pst_contextsub;
1081 	fpst->format = pst_glyphs;
1082 	fpst->subtable = subtable;
1083 	fpst->next = info->possub;
1084 	info->possub = fpst;
1085 	subtable->fpst = fpst;
1086 
1087 	fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1088 	fpst->rule_cnt = cnt;
1089 
1090 	cnt = 0;
1091 	for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1092 	    rule[cnt].u.glyph.names = GlyphsToNames(info,rules[i].subrules[j].glyphs,false);
1093 	    rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1094 	    rule[cnt].lookups = rules[i].subrules[j].sl;
1095 	    rules[i].subrules[j].sl = NULL;
1096 	    for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1097 		ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1098 	    ++cnt;
1099 	}
1100     }
1101 
1102     for ( i=0; i<rcnt; ++i ) {
1103 	for ( j=0; j<rules[i].scnt; ++j ) {
1104 	    free(rules[i].subrules[j].glyphs);
1105 	    free(rules[i].subrules[j].sl);
1106 	}
1107 	free(rules[i].subrules);
1108     }
1109     free(rules);
1110     free(glyphs);
1111 }
1112 
g___ChainingSubTable1(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks,int gpos)1113 static void g___ChainingSubTable1(FILE *ttf, int stoffset,
1114 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1115 	struct lookup *alllooks, int gpos) {
1116     int i, j, k, rcnt, cnt, which;
1117     uint16 coverage;
1118     uint16 *glyphs;
1119     struct subrule {
1120 	uint32 offset;
1121 	int gcnt, bcnt, fcnt;
1122 	int scnt;
1123 	uint16 *glyphs, *bglyphs, *fglyphs;
1124 	struct seqlookup *sl;
1125     };
1126     struct rule {
1127 	uint32 offsets;
1128 	int scnt;
1129 	struct subrule *subrules;
1130     } *rules;
1131     FPST *fpst;
1132     struct fpst_rule *rule;
1133     int warned = false, warned2 = false;
1134     (void)l; /* for -Wall */
1135     coverage = getushort(ttf);
1136     rcnt = getushort(ttf);		/* glyph count in coverage table */
1137     rules = galloc(rcnt*sizeof(struct rule));
1138     for ( i=0; i<rcnt; ++i )
1139 	rules[i].offsets = getushort(ttf)+stoffset;
1140     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1141     if ( glyphs==NULL ) {
1142 	free(rules);
1143 return;
1144     }
1145     cnt = 0;
1146     for ( i=0; i<rcnt; ++i ) {
1147 	fseek(ttf,rules[i].offsets,SEEK_SET);
1148 	rules[i].scnt = getushort(ttf);
1149 	cnt += rules[i].scnt;
1150 	rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1151 	for ( j=0; j<rules[i].scnt; ++j )
1152 	    rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1153 	for ( j=0; j<rules[i].scnt; ++j ) {
1154 	    fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1155 	    rules[i].subrules[j].bcnt = getushort(ttf);
1156 	    if ( feof(ttf)) {
1157 		LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1158 		info->bad_ot = true;
1159 return;
1160 	    }
1161 	    rules[i].subrules[j].bglyphs = galloc((rules[i].subrules[j].bcnt+1)*sizeof(uint16));
1162 	    for ( k=0; k<rules[i].subrules[j].bcnt; ++k )
1163 		rules[i].subrules[j].bglyphs[k] = getushort(ttf);
1164 	    rules[i].subrules[j].bglyphs[k] = 0xffff;
1165 
1166 	    rules[i].subrules[j].gcnt = getushort(ttf);
1167 	    if ( feof(ttf)) {
1168 		LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1169 		info->bad_ot = true;
1170 return;
1171 	    }
1172 	    rules[i].subrules[j].glyphs = galloc((rules[i].subrules[j].gcnt+1)*sizeof(uint16));
1173 	    rules[i].subrules[j].glyphs[0] = glyphs[i];
1174 	    for ( k=1; k<rules[i].subrules[j].gcnt; ++k )
1175 		rules[i].subrules[j].glyphs[k] = getushort(ttf);
1176 	    rules[i].subrules[j].glyphs[k] = 0xffff;
1177 
1178 	    rules[i].subrules[j].fcnt = getushort(ttf);
1179 	    if ( feof(ttf)) {
1180 		LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1181 		info->bad_ot = true;
1182 return;
1183 	    }
1184 	    rules[i].subrules[j].fglyphs = galloc((rules[i].subrules[j].fcnt+1)*sizeof(uint16));
1185 	    for ( k=0; k<rules[i].subrules[j].fcnt; ++k )
1186 		rules[i].subrules[j].fglyphs[k] = getushort(ttf);
1187 	    rules[i].subrules[j].fglyphs[k] = 0xffff;
1188 
1189 	    for ( which = 0; which<3; ++which ) {
1190 		for ( k=0; k<(&rules[i].subrules[j].gcnt)[which]; ++k ) {
1191 		    if ( (&rules[i].subrules[j].glyphs)[which][k]>=info->glyph_cnt ) {
1192 			if ( !warned )
1193 			    LogError( _("Bad contextual or chaining sub table. Glyph %d out of range [0,%d)\n"),
1194 				    (&rules[i].subrules[j].glyphs)[which][k], info->glyph_cnt );
1195 			info->bad_ot = true;
1196 			warned = true;
1197 			(&rules[i].subrules[j].glyphs)[which][k] = 0;
1198 		    }
1199 		}
1200 	    }
1201 
1202 	    rules[i].subrules[j].scnt = getushort(ttf);
1203 	    if ( feof(ttf)) {
1204 		LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1205 		info->bad_ot = true;
1206 return;
1207 	    }
1208 	    rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1209 	    for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1210 		rules[i].subrules[j].sl[k].seq = getushort(ttf);
1211 		if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].gcnt+1 )
1212 		    if ( !warned2 ) {
1213 			LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1214 				rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].gcnt );
1215 			info->bad_ot = true;
1216 			warned2 = true;
1217 		    }
1218 		rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1219 	    }
1220 	}
1221     }
1222 
1223     if ( justinuse==git_justinuse ) {
1224 	/* Nothing to do. This lookup doesn't really reference any glyphs */
1225 	/*  any lookups it invokes will be processed on their own */
1226     } else {
1227 	fpst = chunkalloc(sizeof(FPST));
1228 	fpst->type = gpos ? pst_chainpos : pst_chainsub;
1229 	fpst->format = pst_glyphs;
1230 	fpst->subtable = subtable;
1231 	fpst->next = info->possub;
1232 	info->possub = fpst;
1233 	subtable->fpst = fpst;
1234 
1235 	fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1236 	fpst->rule_cnt = cnt;
1237 
1238 	cnt = 0;
1239 	for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1240 	    rule[cnt].u.glyph.back = GlyphsToNames(info,rules[i].subrules[j].bglyphs,false);
1241 	    rule[cnt].u.glyph.names = GlyphsToNames(info,rules[i].subrules[j].glyphs,false);
1242 	    rule[cnt].u.glyph.fore = GlyphsToNames(info,rules[i].subrules[j].fglyphs,false);
1243 	    rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1244 	    rule[cnt].lookups = rules[i].subrules[j].sl;
1245 	    rules[i].subrules[j].sl = NULL;
1246 	    for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1247 		ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1248 	    ++cnt;
1249 	}
1250     }
1251 
1252     for ( i=0; i<rcnt; ++i ) {
1253 	for ( j=0; j<rules[i].scnt; ++j ) {
1254 	    free(rules[i].subrules[j].bglyphs);
1255 	    free(rules[i].subrules[j].glyphs);
1256 	    free(rules[i].subrules[j].fglyphs);
1257 	    free(rules[i].subrules[j].sl);
1258 	}
1259 	free(rules[i].subrules);
1260     }
1261     free(rules);
1262     free(glyphs);
1263 }
1264 
g___ContextSubTable2(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks,int gpos)1265 static void g___ContextSubTable2(FILE *ttf, int stoffset,
1266 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1267 	struct lookup *alllooks, int gpos) {
1268     int i, j, k, rcnt, cnt;
1269     uint16 coverage;
1270     uint16 classoff;
1271     struct subrule {
1272 	uint32 offset;
1273 	int ccnt;
1274 	int scnt;
1275 	uint16 *classindeces;
1276 	struct seqlookup *sl;
1277     };
1278     struct rule {
1279 	uint32 offsets;
1280 	int scnt;
1281 	struct subrule *subrules;
1282     } *rules;
1283     FPST *fpst;
1284     struct fpst_rule *rule;
1285     uint16 *glyphs, *class;
1286     int warned2 = false;
1287     (void)l; /* for -Wall */
1288     coverage = getushort(ttf);
1289     classoff = getushort(ttf);
1290     rcnt = getushort(ttf);		/* class count in coverage table *//* == number of top level rules */
1291     rules = gcalloc(rcnt,sizeof(struct rule));
1292     for ( i=0; i<rcnt; ++i )
1293 	rules[i].offsets = getushort(ttf)+stoffset;
1294     cnt = 0;
1295     for ( i=0; i<rcnt; ++i ) if ( rules[i].offsets!=(unsigned)stoffset ) { /* some classes might be unused */
1296 	fseek(ttf,rules[i].offsets,SEEK_SET);
1297 	rules[i].scnt = getushort(ttf);
1298 	if ( rules[i].scnt<0 ) {
1299 	    LogError( _("Bad count in context chaining sub-table.\n") );
1300 	    info->bad_ot = true;
1301 return;
1302 	}
1303 	cnt += rules[i].scnt;
1304 	rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1305 	for ( j=0; j<rules[i].scnt; ++j )
1306 	    rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1307 	for ( j=0; j<rules[i].scnt; ++j ) {
1308 	    fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1309 	    rules[i].subrules[j].ccnt = getushort(ttf);
1310 	    rules[i].subrules[j].scnt = getushort(ttf);
1311 	    if ( rules[i].subrules[j].ccnt<0 ) {
1312 		LogError( _("Bad class count in contextual chaining sub-table.\n") );
1313 		info->bad_ot = true;
1314 		free(rules);
1315 return;
1316 	    }
1317 	    rules[i].subrules[j].classindeces = galloc(rules[i].subrules[j].ccnt*sizeof(uint16));
1318 	    rules[i].subrules[j].classindeces[0] = i;
1319 	    for ( k=1; k<rules[i].subrules[j].ccnt; ++k )
1320 		rules[i].subrules[j].classindeces[k] = getushort(ttf);
1321 	    if ( rules[i].subrules[j].scnt<0 ) {
1322 		LogError( _("Bad count in contextual chaining sub-table.\n") );
1323 		info->bad_ot = true;
1324 		free(rules);
1325 return;
1326 	    }
1327 	    rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1328 	    for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1329 		rules[i].subrules[j].sl[k].seq = getushort(ttf);
1330 		if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].ccnt )
1331 		    if ( !warned2 ) {
1332 			LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1333 				rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].ccnt-1);
1334 			info->bad_ot = true;
1335 			warned2 = true;
1336 		    }
1337 		rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1338 	    }
1339 	}
1340     }
1341 
1342     if ( justinuse==git_justinuse ) {
1343 	/* Nothing to do. This lookup doesn't really reference any glyphs */
1344 	/*  any lookups it invokes will be processed on their own */
1345     } else {
1346 	fpst = chunkalloc(sizeof(FPST));
1347 	fpst->type = gpos ? pst_contextpos : pst_contextsub;
1348 	fpst->format = pst_class;
1349 	fpst->subtable = subtable;
1350 	subtable->fpst = fpst;
1351 	fpst->next = info->possub;
1352 	info->possub = fpst;
1353 
1354 	fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1355 	fpst->rule_cnt = cnt;
1356 	class = getClassDefTable(ttf, stoffset+classoff, info);
1357 	fpst->nccnt = ClassFindCnt(class,info->glyph_cnt);
1358 	fpst->nclass = ClassToNames(info,fpst->nccnt,class,info->glyph_cnt);
1359 
1360 	/* Just in case they used the coverage table to redefine class 0 */
1361 	glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1362 	fpst->nclass[0] = CoverageMinusClasses(glyphs,class,info);
1363 	free(glyphs); free(class); class = NULL;
1364 
1365 	cnt = 0;
1366 	for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1367 	    rule[cnt].u.class.nclasses = rules[i].subrules[j].classindeces;
1368 	    rule[cnt].u.class.ncnt = rules[i].subrules[j].ccnt;
1369 	    rules[i].subrules[j].classindeces = NULL;
1370 	    rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1371 	    rule[cnt].lookups = rules[i].subrules[j].sl;
1372 	    rules[i].subrules[j].sl = NULL;
1373 	    for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1374 		ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1375 	    ++cnt;
1376 	}
1377     }
1378 
1379     for ( i=0; i<rcnt; ++i ) {
1380 	for ( j=0; j<rules[i].scnt; ++j ) {
1381 	    free(rules[i].subrules[j].classindeces);
1382 	    free(rules[i].subrules[j].sl);
1383 	}
1384 	free(rules[i].subrules);
1385     }
1386     free(rules);
1387 }
1388 
g___ChainingSubTable2(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks,int gpos)1389 static void g___ChainingSubTable2(FILE *ttf, int stoffset,
1390 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1391 	struct lookup *alllooks, int gpos) {
1392     int i, j, k, rcnt, cnt;
1393     uint16 coverage, offset;
1394     uint16 bclassoff, classoff, fclassoff;
1395     struct subrule {
1396 	uint32 offset;
1397 	int ccnt, bccnt, fccnt;
1398 	int scnt;
1399 	uint16 *classindeces, *bci, *fci;
1400 	struct seqlookup *sl;
1401     };
1402     struct rule {
1403 	uint32 offsets;
1404 	int scnt;
1405 	struct subrule *subrules;
1406     } *rules;
1407     FPST *fpst;
1408     struct fpst_rule *rule;
1409     uint16 *glyphs, *class;
1410     int warned2 = false;
1411     (void)l; /* for -Wall */
1412     coverage = getushort(ttf);
1413     bclassoff = getushort(ttf);
1414     classoff = getushort(ttf);
1415     fclassoff = getushort(ttf);
1416     rcnt = getushort(ttf);		/* class count *//* == max number of top level rules */
1417     rules = gcalloc(rcnt,sizeof(struct rule));
1418     for ( i=0; i<rcnt; ++i ) {
1419 	offset = getushort(ttf);
1420 	rules[i].offsets = offset==0 ? 0 : offset+stoffset;
1421     }
1422     cnt = 0;
1423     for ( i=0; i<rcnt; ++i ) if ( rules[i].offsets!=0 ) { /* some classes might be unused */
1424 	fseek(ttf,rules[i].offsets,SEEK_SET);
1425 	rules[i].scnt = getushort(ttf);
1426 	if ( rules[i].scnt<0 ) {
1427 	    LogError( _("Bad count in context chaining sub-table.\n") );
1428 	    info->bad_ot = true;
1429 return;
1430 	}
1431 	cnt += rules[i].scnt;
1432 	rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1433 	for ( j=0; j<rules[i].scnt; ++j )
1434 	    rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1435 	for ( j=0; j<rules[i].scnt; ++j ) {
1436 	    fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1437 	    rules[i].subrules[j].bccnt = getushort(ttf);
1438 	    if ( rules[i].subrules[j].bccnt<0 ) {
1439 		LogError( _("Bad class count in contextual chaining sub-table.\n") );
1440 		info->bad_ot = true;
1441 		free(rules);
1442 return;
1443 	    }
1444 	    rules[i].subrules[j].bci = galloc(rules[i].subrules[j].bccnt*sizeof(uint16));
1445 	    for ( k=0; k<rules[i].subrules[j].bccnt; ++k )
1446 		rules[i].subrules[j].bci[k] = getushort(ttf);
1447 	    rules[i].subrules[j].ccnt = getushort(ttf);
1448 	    if ( rules[i].subrules[j].ccnt<0 ) {
1449 		LogError( _("Bad class count in contextual chaining sub-table.\n") );
1450 		info->bad_ot = true;
1451 		free(rules);
1452 return;
1453 	    }
1454 	    rules[i].subrules[j].classindeces = galloc(rules[i].subrules[j].ccnt*sizeof(uint16));
1455 	    rules[i].subrules[j].classindeces[0] = i;
1456 	    for ( k=1; k<rules[i].subrules[j].ccnt; ++k )
1457 		rules[i].subrules[j].classindeces[k] = getushort(ttf);
1458 	    rules[i].subrules[j].fccnt = getushort(ttf);
1459 	    if ( rules[i].subrules[j].fccnt<0 ) {
1460 		LogError( _("Bad class count in contextual chaining sub-table.\n") );
1461 		info->bad_ot = true;
1462 		free(rules);
1463 return;
1464 	    }
1465 	    rules[i].subrules[j].fci = galloc(rules[i].subrules[j].fccnt*sizeof(uint16));
1466 	    for ( k=0; k<rules[i].subrules[j].fccnt; ++k )
1467 		rules[i].subrules[j].fci[k] = getushort(ttf);
1468 	    rules[i].subrules[j].scnt = getushort(ttf);
1469 	    if ( rules[i].subrules[j].scnt<0 ) {
1470 		LogError( _("Bad count in contextual chaining sub-table.\n") );
1471 		info->bad_ot = true;
1472 		free(rules);
1473 return;
1474 	    }
1475 	    rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1476 	    for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1477 		rules[i].subrules[j].sl[k].seq = getushort(ttf);
1478 		if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].ccnt )
1479 		    if ( !warned2 ) {
1480 			LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1481 				rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].ccnt-1);
1482 			info->bad_ot = true;
1483 			warned2 = true;
1484 		    }
1485 		rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1486 	    }
1487 	}
1488     }
1489 
1490     if ( justinuse==git_justinuse ) {
1491 	/* Nothing to do. This lookup doesn't really reference any glyphs */
1492 	/*  any lookups it invokes will be processed on their own */
1493     } else {
1494 	fpst = chunkalloc(sizeof(FPST));
1495 	fpst->type = gpos ? pst_chainpos : pst_chainsub;
1496 	fpst->format = pst_class;
1497 	fpst->subtable = subtable;
1498 	subtable->fpst = fpst;
1499 	fpst->next = info->possub;
1500 	info->possub = fpst;
1501 
1502 	fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1503 	fpst->rule_cnt = cnt;
1504 
1505 	class = getClassDefTable(ttf, stoffset+classoff, info);
1506 	fpst->nccnt = ClassFindCnt(class,info->glyph_cnt);
1507 	fpst->nclass = ClassToNames(info,fpst->nccnt,class,info->glyph_cnt);
1508 
1509 	/* Just in case they used the coverage table to redefine class 0 */
1510 	glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1511 	fpst->nclass[0] = CoverageMinusClasses(glyphs,class,info);
1512 	free(glyphs); free(class); class = NULL;
1513 
1514 	/* The docs don't mention this, but in mangal.ttf fclassoff==0 NULL */
1515 	if ( bclassoff!=0 )
1516 	    class = getClassDefTable(ttf, stoffset+bclassoff, info);
1517 	else
1518 	    class = gcalloc(info->glyph_cnt,sizeof(uint16));
1519 	fpst->bccnt = ClassFindCnt(class,info->glyph_cnt);
1520 	fpst->bclass = ClassToNames(info,fpst->bccnt,class,info->glyph_cnt);
1521 	free(class);
1522 	if ( fclassoff!=0 )
1523 	    class = getClassDefTable(ttf, stoffset+fclassoff, info);
1524 	else
1525 	    class = gcalloc(info->glyph_cnt,sizeof(uint16));
1526 	fpst->fccnt = ClassFindCnt(class,info->glyph_cnt);
1527 	fpst->fclass = ClassToNames(info,fpst->fccnt,class,info->glyph_cnt);
1528 	free(class);
1529 
1530 	cnt = 0;
1531 	for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1532 	    rule[cnt].u.class.nclasses = rules[i].subrules[j].classindeces;
1533 	    rule[cnt].u.class.ncnt = rules[i].subrules[j].ccnt;
1534 	    rules[i].subrules[j].classindeces = NULL;
1535 	    rule[cnt].u.class.bclasses = rules[i].subrules[j].bci;
1536 	    rule[cnt].u.class.bcnt = rules[i].subrules[j].bccnt;
1537 	    rules[i].subrules[j].bci = NULL;
1538 	    rule[cnt].u.class.fclasses = rules[i].subrules[j].fci;
1539 	    rule[cnt].u.class.fcnt = rules[i].subrules[j].fccnt;
1540 	    rules[i].subrules[j].fci = NULL;
1541 	    rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1542 	    rule[cnt].lookups = rules[i].subrules[j].sl;
1543 	    rules[i].subrules[j].sl = NULL;
1544 	    for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1545 		ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1546 	    ++cnt;
1547 	}
1548     }
1549 
1550     for ( i=0; i<rcnt; ++i ) {
1551 	for ( j=0; j<rules[i].scnt; ++j ) {
1552 	    free(rules[i].subrules[j].classindeces);
1553 	    free(rules[i].subrules[j].sl);
1554 	}
1555 	free(rules[i].subrules);
1556     }
1557     free(rules);
1558 }
1559 
g___ContextSubTable3(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks,int gpos)1560 static void g___ContextSubTable3(FILE *ttf, int stoffset,
1561 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1562 	struct lookup *alllooks, int gpos) {
1563     int i, k, scnt, gcnt;
1564     uint16 *coverage;
1565     struct seqlookup *sl;
1566     uint16 *glyphs;
1567     FPST *fpst;
1568     struct fpst_rule *rule;
1569     int warned2 = false;
1570     (void)l; /* for -Wall */
1571     gcnt = getushort(ttf);
1572     scnt = getushort(ttf);
1573     if ( feof(ttf) ) {
1574 	LogError( _("End of file in context chaining sub-table.\n") );
1575 	info->bad_ot = true;
1576 return;
1577     }
1578     coverage = galloc(gcnt*sizeof(uint16));
1579     for ( i=0; i<gcnt; ++i )
1580 	coverage[i] = getushort(ttf);
1581     sl = galloc(scnt*sizeof(struct seqlookup));
1582     for ( k=0; k<scnt; ++k ) {
1583 	sl[k].seq = getushort(ttf);
1584 	if ( sl[k].seq >= gcnt && !warned2 ) {
1585 	    LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d, max=%d\n"),
1586 		    sl[k].seq, gcnt-1 );
1587 	    info->bad_ot = true;
1588 	    warned2 = true;
1589 	}
1590 	sl[k].lookup = (void *) (intpt) getushort(ttf);
1591     }
1592 
1593     if ( justinuse==git_justinuse ) {
1594 	/* Nothing to do. This lookup doesn't really reference any glyphs */
1595 	/*  any lookups it invokes will be processed on their own */
1596     } else {
1597 	fpst = chunkalloc(sizeof(FPST));
1598 	fpst->type = gpos ? pst_contextpos : pst_contextsub;
1599 	fpst->format = pst_coverage;
1600 	fpst->subtable = subtable;
1601 	subtable->fpst = fpst;
1602 	fpst->next = info->possub;
1603 	info->possub = fpst;
1604 
1605 	fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
1606 	fpst->rule_cnt = 1;
1607 	rule->u.coverage.ncnt = gcnt;
1608 	rule->u.coverage.ncovers = galloc(gcnt*sizeof(char **));
1609 	for ( i=0; i<gcnt; ++i ) {
1610 	    glyphs =  getCoverageTable(ttf,stoffset+coverage[i],info);
1611 	    rule->u.coverage.ncovers[i] = GlyphsToNames(info,glyphs,true);
1612 	    free(glyphs);
1613 	}
1614 	rule->lookup_cnt = scnt;
1615 	rule->lookups = sl;
1616 	for ( k=0; k<scnt; ++k )
1617 	    ProcessSubLookups(ttf,info,gpos,alllooks,&sl[k]);
1618     }
1619 
1620     free(coverage);
1621 }
1622 
g___ChainingSubTable3(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks,int gpos)1623 static void g___ChainingSubTable3(FILE *ttf, int stoffset,
1624 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1625 	struct lookup *alllooks, int gpos) {
1626     int i, k, scnt, gcnt, bcnt, fcnt;
1627     uint16 *coverage, *bcoverage, *fcoverage;
1628     struct seqlookup *sl;
1629     uint16 *glyphs;
1630     FPST *fpst;
1631     struct fpst_rule *rule;
1632     int warned2 = false;
1633     (void)l; /* for -Wall */
1634     bcnt = getushort(ttf);
1635     if ( feof(ttf)) {
1636 	LogError( _("End of file in context chaining subtable.\n") );
1637 	info->bad_ot = true;
1638 return;
1639     }
1640     bcoverage = galloc(bcnt*sizeof(uint16));
1641     for ( i=0; i<bcnt; ++i )
1642 	bcoverage[i] = getushort(ttf);
1643     gcnt = getushort(ttf);
1644     if ( feof(ttf)) {
1645 	LogError( _("End of file in context chaining subtable.\n") );
1646 	info->bad_ot = true;
1647 return;
1648     }
1649     coverage = galloc(gcnt*sizeof(uint16));
1650     for ( i=0; i<gcnt; ++i )
1651 	coverage[i] = getushort(ttf);
1652     fcnt = getushort(ttf);
1653     if ( feof(ttf)) {
1654 	LogError( _("End of file in context chaining subtable.\n") );
1655 	info->bad_ot = true;
1656 return;
1657     }
1658     fcoverage = galloc(fcnt*sizeof(uint16));
1659     for ( i=0; i<fcnt; ++i )
1660 	fcoverage[i] = getushort(ttf);
1661     scnt = getushort(ttf);
1662     if ( feof(ttf)) {
1663 	LogError( _("End of file in context chaining subtable.\n") );
1664 	info->bad_ot = true;
1665 return;
1666     }
1667     sl = galloc(scnt*sizeof(struct seqlookup));
1668     for ( k=0; k<scnt; ++k ) {
1669 	sl[k].seq = getushort(ttf);
1670 	if ( sl[k].seq >= gcnt && !warned2 ) {
1671 	    LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d, max=%d\n"),
1672 		    sl[k].seq, gcnt-1 );
1673 	    info->bad_ot = true;
1674 	    warned2 = true;
1675 	}
1676 	sl[k].lookup = (void *) (intpt) getushort(ttf);
1677     }
1678 
1679     if ( justinuse==git_justinuse ) {
1680 	/* Nothing to do. This lookup doesn't really reference any glyphs */
1681 	/*  any lookups it invokes will be processed on their own */
1682     } else {
1683 	fpst = chunkalloc(sizeof(FPST));
1684 	fpst->type = gpos ? pst_chainpos : pst_chainsub;
1685 	fpst->format = pst_coverage;
1686 	fpst->subtable = subtable;
1687 	subtable->fpst = fpst;
1688 	fpst->next = info->possub;
1689 	info->possub = fpst;
1690 
1691 	fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
1692 	fpst->rule_cnt = 1;
1693 
1694 	rule->u.coverage.bcnt = bcnt;
1695 	rule->u.coverage.bcovers = galloc(bcnt*sizeof(char **));
1696 	for ( i=0; i<bcnt; ++i ) {
1697 	    glyphs =  getCoverageTable(ttf,stoffset+bcoverage[i],info);
1698 	    rule->u.coverage.bcovers[i] = GlyphsToNames(info,glyphs,true);
1699 	    free(glyphs);
1700 	}
1701 
1702 	rule->u.coverage.ncnt = gcnt;
1703 	rule->u.coverage.ncovers = galloc(gcnt*sizeof(char **));
1704 	for ( i=0; i<gcnt; ++i ) {
1705 	    glyphs =  getCoverageTable(ttf,stoffset+coverage[i],info);
1706 	    rule->u.coverage.ncovers[i] = GlyphsToNames(info,glyphs,true);
1707 	    free(glyphs);
1708 	}
1709 
1710 	rule->u.coverage.fcnt = fcnt;
1711 	rule->u.coverage.fcovers = galloc(fcnt*sizeof(char **));
1712 	for ( i=0; i<fcnt; ++i ) {
1713 	    glyphs =  getCoverageTable(ttf,stoffset+fcoverage[i],info);
1714 	    rule->u.coverage.fcovers[i] = GlyphsToNames(info,glyphs,true);
1715 	    free(glyphs);
1716 	}
1717 
1718 	rule->lookup_cnt = scnt;
1719 	rule->lookups = sl;
1720 	for ( k=0; k<scnt; ++k )
1721 	    ProcessSubLookups(ttf,info,gpos,alllooks,&sl[k]);
1722     }
1723 
1724     free(bcoverage);
1725     free(coverage);
1726     free(fcoverage);
1727 }
1728 
gposContextSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,struct lookup * alllooks)1729 static void gposContextSubTable(FILE *ttf, int stoffset,
1730 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
1731 	struct lookup *alllooks) {
1732     switch( getushort(ttf)) {
1733       case 1:
1734 	g___ContextSubTable1(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1735       break;
1736       case 2:
1737 	g___ContextSubTable2(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1738       break;
1739       case 3:
1740 	g___ContextSubTable3(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1741       break;
1742     }
1743 }
1744 
gposChainingSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,struct lookup * alllooks)1745 static void gposChainingSubTable(FILE *ttf, int stoffset,
1746 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
1747 	struct lookup *alllooks) {
1748     switch( getushort(ttf)) {
1749       case 1:
1750 	g___ChainingSubTable1(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1751       break;
1752       case 2:
1753 	g___ChainingSubTable2(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1754       break;
1755       case 3:
1756 	g___ChainingSubTable3(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1757       break;
1758     }
1759 }
1760 
1761 static struct { uint32 tag; char *str; } tagstr[] = {
1762     { CHR('v','r','t','2'), "vert" },
1763     { CHR('s','m','c','p'), "sc" },
1764     { CHR('s','m','c','p'), "small" },
1765     { CHR('o','n','u','m'), "oldstyle" },
1766     { CHR('s','u','p','s'), "superior" },
1767     { CHR('s','u','b','s'), "inferior" },
1768     { CHR('s','w','s','h'), "swash" },
1769     { 0, NULL }
1770 };
1771 
1772 
gsubSimpleSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse)1773 static void gsubSimpleSubTable(FILE *ttf, int stoffset, struct ttfinfo *info,
1774 	struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
1775     int coverage, cnt, i, j, which;
1776     uint16 format;
1777     uint16 *glyphs, *glyph2s=NULL;
1778     int delta=0;
1779 
1780     format=getushort(ttf);
1781     if ( format!=1 && format!=2 )	/* Unknown subtable format */
1782 return;
1783     coverage = getushort(ttf);
1784     if ( format==1 ) {
1785 	delta = getushort(ttf);
1786     } else {
1787 	cnt = getushort(ttf);
1788 	glyph2s = galloc(cnt*sizeof(uint16));
1789 	for ( i=0; i<cnt; ++i )
1790 	    glyph2s[i] = getushort(ttf);
1791 	    /* in range check comes later */
1792     }
1793     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1794     if ( glyphs==NULL ) {
1795 	free(glyph2s);
1796 return;
1797     }
1798     if ( justinuse==git_findnames ) {
1799 	FeatureScriptLangList *fl;
1800 	fl = l->otlookup->features;
1801 	/* Unnamed glyphs get a name built of the base name and the feature tag */
1802 	/*  assuming this lookup is tagged with a feature... */
1803 	if ( fl!=NULL )
1804 	for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
1805 	    if ( info->chars[glyphs[i]]->name!=NULL ) {
1806 		which = format==1 ? (uint16) (glyphs[i]+delta) : glyph2s[i];
1807 		if ( which<info->glyph_cnt && which>=0 && info->chars[which]!=NULL &&
1808 			info->chars[which]->name==NULL ) {
1809 		    char *basename = info->chars[glyphs[i]]->name;
1810 		    char *str;
1811 		    char tag[5], *pt=tag;
1812 		    for ( j=0; tagstr[j].tag!=0 && tagstr[j].tag!=fl->featuretag; ++j );
1813 		    if ( tagstr[j].tag!=0 )
1814 			pt = tagstr[j].str;
1815 		    else {
1816 			tag[0] = fl->featuretag>>24;
1817 			if ( (tag[1] = (fl->featuretag>>16)&0xff)==' ' ) tag[1] = '\0';
1818 			if ( (tag[2] = (fl->featuretag>>8)&0xff)==' ' ) tag[2] = '\0';
1819 			if ( (tag[3] = (fl->featuretag)&0xff)==' ' ) tag[3] = '\0';
1820 			tag[4] = '\0';
1821 			pt = tag;
1822 		    }
1823 		    str = galloc(strlen(basename)+strlen(pt)+2);
1824 		    sprintf(str,"%s.%s", basename, pt );
1825 		    info->chars[which]->name = str;
1826 		}
1827 	    }
1828 	}
1829     } else if ( justinuse==git_justinuse ) {
1830 	for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
1831 	    info->inuse[glyphs[i]]= true;
1832 	    which = format==1 ? (uint16) (glyphs[i]+delta) : glyph2s[i];
1833 	    info->inuse[which]= true;
1834 	}
1835     } else if ( justinuse==git_normal ) {
1836 	for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt && info->chars[glyphs[i]]!=NULL ) {
1837 	    which = format==1 ? (uint16) (glyphs[i]+delta) : glyph2s[i];
1838 	    if ( which>=info->glyph_cnt ) {
1839 		LogError( _("Bad substitution glyph: GID %d not less than %d\n"),
1840 			which, info->glyph_cnt);
1841 		info->bad_ot = true;
1842 		which = 0;
1843 	    }
1844 	    if ( info->chars[which]!=NULL ) {	/* Might be in a ttc file */
1845 		PST *pos = chunkalloc(sizeof(PST));
1846 		pos->type = pst_substitution;
1847 		pos->subtable = subtable;
1848 		pos->next = info->chars[glyphs[i]]->possub;
1849 		info->chars[glyphs[i]]->possub = pos;
1850 		pos->u.subs.variant = copy(info->chars[which]->name);
1851 	    }
1852 	}
1853     }
1854     subtable->per_glyph_pst_or_kern = true;
1855     free(glyph2s);
1856     free(glyphs);
1857 }
1858 
1859 /* Multiple and alternate substitution lookups have the same format */
gsubMultipleSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse)1860 static void gsubMultipleSubTable(FILE *ttf, int stoffset, struct ttfinfo *info,
1861 	struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
1862     int coverage, cnt, i, j, len, max;
1863     uint16 format;
1864     uint16 *offsets;
1865     uint16 *glyphs, *glyph2s;
1866     char *pt;
1867     int bad;
1868     int badcnt = 0;
1869 
1870     if ( justinuse==git_findnames )
1871 return;
1872 
1873     format=getushort(ttf);
1874     if ( format!=1 )	/* Unknown subtable format */
1875 return;
1876     coverage = getushort(ttf);
1877     cnt = getushort(ttf);
1878     if ( feof(ttf)) {
1879 	LogError( _("Unexpected end of file in GSUB sub-table.\n"));
1880 	info->bad_ot = true;
1881 return;
1882     }
1883     offsets = galloc(cnt*sizeof(uint16));
1884     for ( i=0; i<cnt; ++i )
1885 	offsets[i] = getushort(ttf);
1886     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1887     if ( glyphs==NULL ) {
1888 	free(offsets);
1889 return;
1890     }
1891     for ( i=0; glyphs[i]!=0xffff; ++i );
1892     if ( i!=cnt ) {
1893 	LogError( _("Coverage table specifies a different number of glyphs than the sub-table expects.\n" ));
1894 	info->bad_ot = true;
1895 	if ( cnt<i )
1896 	    glyphs[cnt] = 0xffff;
1897 	else
1898 	    cnt = i;
1899     }
1900     max = 20;
1901     glyph2s = galloc(max*sizeof(uint16));
1902     for ( i=0; glyphs[i]!=0xffff; ++i ) {
1903 	PST *alt;
1904 	fseek(ttf,stoffset+offsets[i],SEEK_SET);
1905 	cnt = getushort(ttf);
1906 	if ( feof(ttf)) {
1907 	    LogError( _("Unexpected end of file in GSUB sub-table.\n"));
1908 	    info->bad_ot = true;
1909 return;
1910 	}
1911 	if ( cnt>max ) {
1912 	    max = cnt+30;
1913 	    glyph2s = grealloc(glyph2s,max*sizeof(uint16));
1914 	}
1915 	len = 0; bad = false;
1916 	for ( j=0; j<cnt; ++j ) {
1917 	    glyph2s[j] = getushort(ttf);
1918 	    if ( feof(ttf)) {
1919 		LogError( _("Unexpected end of file in GSUB sub-table.\n" ));
1920 		info->bad_ot = true;
1921 return;
1922 	    }
1923 	    if ( glyph2s[j]>=info->glyph_cnt ) {
1924 		if ( !justinuse )
1925 		    LogError( _("Bad Multiple/Alternate substitution glyph. GID %d not less than %d\n"),
1926 			    glyph2s[j], info->glyph_cnt );
1927 		info->bad_ot = true;
1928 		if ( ++badcnt>20 )
1929 return;
1930 		glyph2s[j] = 0;
1931 	    }
1932 	    if ( justinuse==git_justinuse )
1933 		/* Do Nothing */;
1934 	    else if ( info->chars[glyph2s[j]]==NULL )
1935 		bad = true;
1936 	    else
1937 		len += strlen( info->chars[glyph2s[j]]->name) +1;
1938 	}
1939 	if ( justinuse==git_justinuse ) {
1940 	    info->inuse[glyphs[i]] = 1;
1941 	    for ( j=0; j<cnt; ++j )
1942 		info->inuse[glyph2s[j]] = 1;
1943 	} else if ( info->chars[glyphs[i]]!=NULL && !bad ) {
1944 	    alt = chunkalloc(sizeof(PST));
1945 	    alt->type = l->otlookup->lookup_type==gsub_multiple?pst_multiple:pst_alternate;
1946 	    alt->subtable = subtable;
1947 	    alt->next = info->chars[glyphs[i]]->possub;
1948 	    info->chars[glyphs[i]]->possub = alt;
1949 	    pt = alt->u.subs.variant = galloc(len+1);
1950 	    *pt = '\0';
1951 	    for ( j=0; j<cnt; ++j ) {
1952 		strcat(pt,info->chars[glyph2s[j]]->name);
1953 		strcat(pt," ");
1954 	    }
1955 	    if ( *pt!='\0' && pt[strlen(pt)-1]==' ' )
1956 		pt[strlen(pt)-1] = '\0';
1957 	}
1958     }
1959     subtable->per_glyph_pst_or_kern = true;
1960     free(glyphs);
1961     free(glyph2s);
1962     free(offsets);
1963 }
1964 
gsubLigatureSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse)1965 static void gsubLigatureSubTable(FILE *ttf, int stoffset,
1966 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
1967     int coverage, cnt, i, j, k, lig_cnt, cc, len;
1968     uint16 *ls_offsets, *lig_offsets;
1969     uint16 *glyphs, *lig_glyphs, lig;
1970     char *pt;
1971     PST *liga;
1972 
1973     /* Format = */ getushort(ttf);
1974     coverage = getushort(ttf);
1975     cnt = getushort(ttf);
1976     if ( feof(ttf)) {
1977 	LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
1978 	info->bad_ot = true;
1979 return;
1980     }
1981     ls_offsets = galloc(cnt*sizeof(uint16));
1982     for ( i=0; i<cnt; ++i )
1983 	ls_offsets[i]=getushort(ttf);
1984     glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1985     if ( glyphs==NULL )
1986 return;
1987     for ( i=0; i<cnt; ++i ) {
1988 	fseek(ttf,stoffset+ls_offsets[i],SEEK_SET);
1989 	lig_cnt = getushort(ttf);
1990 	if ( feof(ttf)) {
1991 	    LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
1992 	    info->bad_ot = true;
1993 return;
1994 	}
1995 	lig_offsets = galloc(lig_cnt*sizeof(uint16));
1996 	for ( j=0; j<lig_cnt; ++j )
1997 	    lig_offsets[j] = getushort(ttf);
1998 	if ( feof(ttf)) {
1999 	    LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
2000 	    info->bad_ot = true;
2001 return;
2002 	}
2003 	for ( j=0; j<lig_cnt; ++j ) {
2004 	    fseek(ttf,stoffset+ls_offsets[i]+lig_offsets[j],SEEK_SET);
2005 	    lig = getushort(ttf);
2006 	    if ( lig>=info->glyph_cnt ) {
2007 		LogError( _("Bad ligature glyph. GID %d not less than %d\n"),
2008 			lig, info->glyph_cnt );
2009 		info->bad_ot = true;
2010 		lig = 0;
2011 	    }
2012 	    cc = getushort(ttf);
2013 	    if ( cc<0 || cc>100 ) {
2014 		LogError( _("Unlikely count of ligature components (%d), I suspect this ligature sub-\n table is garbage, I'm giving up on it.\n"), cc );
2015 		info->bad_ot = true;
2016 		free(glyphs); free(lig_offsets);
2017 return;
2018 	    }
2019 	    lig_glyphs = galloc(cc*sizeof(uint16));
2020 	    lig_glyphs[0] = glyphs[i];
2021 	    for ( k=1; k<cc; ++k ) {
2022 		lig_glyphs[k] = getushort(ttf);
2023 		if ( lig_glyphs[k]>=info->glyph_cnt ) {
2024 		    if ( justinuse==git_normal )
2025 			LogError( _("Bad ligature component glyph. GID %d not less than %d (in ligature %d)\n"),
2026 				lig_glyphs[k], info->glyph_cnt, lig );
2027 		    info->bad_ot = true;
2028 		    lig_glyphs[k] = 0;
2029 		}
2030 	    }
2031 	    if ( justinuse==git_justinuse ) {
2032 		info->inuse[lig] = 1;
2033 		for ( k=0; k<cc; ++k )
2034 		    info->inuse[lig_glyphs[k]] = 1;
2035 	    } else if ( justinuse==git_findnames ) {
2036 		FeatureScriptLangList *fl = l->otlookup->features;
2037 		/* If our ligature glyph has no name (and its components do) */
2038 		/*  give it a name by concatenating components with underscores */
2039 		/*  between them, and appending the tag */
2040 		if ( fl!=NULL && info->chars[lig]!=NULL && info->chars[lig]->name==NULL ) {
2041 		    int len=0;
2042 		    for ( k=0; k<cc; ++k ) {
2043 			if ( info->chars[lig_glyphs[k]]==NULL || info->chars[lig_glyphs[k]]->name==NULL )
2044 		    break;
2045 			len += strlen(info->chars[lig_glyphs[k]]->name)+1;
2046 		    }
2047 		    if ( k==cc ) {
2048 			char *str = galloc(len+6), *pt;
2049 			char tag[5];
2050 			tag[0] = fl->featuretag>>24;
2051 			if ( (tag[1] = (fl->featuretag>>16)&0xff)==' ' ) tag[1] = '\0';
2052 			if ( (tag[2] = (fl->featuretag>>8)&0xff)==' ' ) tag[2] = '\0';
2053 			if ( (tag[3] = (fl->featuretag)&0xff)==' ' ) tag[3] = '\0';
2054 			tag[4] = '\0';
2055 			*str='\0';
2056 			for ( k=0; k<cc; ++k ) {
2057 			    strcat(str,info->chars[lig_glyphs[k]]->name);
2058 			    strcat(str,"_");
2059 			}
2060 			pt = str+strlen(str);
2061 			pt[-1] = '.';
2062 			strcpy(pt,tag);
2063 			info->chars[lig]->name = str;
2064 		    }
2065 		}
2066 	    } else if ( info->chars[lig]!=NULL ) {
2067 		for ( k=len=0; k<cc; ++k )
2068 		    if ( lig_glyphs[k]<info->glyph_cnt &&
2069 			    info->chars[lig_glyphs[k]]!=NULL )
2070 			len += strlen(info->chars[lig_glyphs[k]]->name)+1;
2071 		liga = chunkalloc(sizeof(PST));
2072 		liga->type = pst_ligature;
2073 		liga->subtable = subtable;
2074 		liga->next = info->chars[lig]->possub;
2075 		info->chars[lig]->possub = liga;
2076 		liga->u.lig.lig = info->chars[lig];
2077 		liga->u.lig.components = pt = galloc(len);
2078 		for ( k=0; k<cc; ++k ) {
2079 		    if ( lig_glyphs[k]<info->glyph_cnt &&
2080 			    info->chars[lig_glyphs[k]]!=NULL ) {
2081 			strcpy(pt,info->chars[lig_glyphs[k]]->name);
2082 			pt += strlen(pt);
2083 			*pt++ = ' ';
2084 		    }
2085 		}
2086 		pt[-1] = '\0';
2087 	    }
2088 	    free(lig_glyphs);
2089 	}
2090 	free(lig_offsets);
2091     }
2092     subtable->per_glyph_pst_or_kern = true;
2093     free(ls_offsets); free(glyphs);
2094 }
2095 
gsubContextSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks)2096 static void gsubContextSubTable(FILE *ttf, int stoffset,
2097 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2098 	struct lookup *alllooks) {
2099     if ( justinuse==git_findnames )
2100 return;		/* Don't give names to these guys, they might not be unique */
2101 	/* ie. because these are context based there is not a one to one */
2102 	/*  mapping between input glyphs and output glyphs. One input glyph */
2103 	/*  may go to several output glyphs (depending on context) and so */
2104 	/*  <input-glyph-name>"."<tag-name> would be used for several glyphs */
2105     switch( getushort(ttf)) {
2106       case 1:
2107 	g___ContextSubTable1(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2108       break;
2109       case 2:
2110 	g___ContextSubTable2(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2111       break;
2112       case 3:
2113 	g___ContextSubTable3(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2114       break;
2115     }
2116 }
2117 
gsubChainingSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks)2118 static void gsubChainingSubTable(FILE *ttf, int stoffset,
2119 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2120 	struct lookup *alllooks) {
2121     if ( justinuse==git_findnames )
2122 return;		/* Don't give names to these guys, the names might not be unique */
2123     switch( getushort(ttf)) {
2124       case 1:
2125 	g___ChainingSubTable1(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2126       break;
2127       case 2:
2128 	g___ChainingSubTable2(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2129       break;
2130       case 3:
2131 	g___ChainingSubTable3(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2132       break;
2133     }
2134 }
2135 
gsubReverseChainSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse)2136 static void gsubReverseChainSubTable(FILE *ttf, int stoffset,
2137 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
2138     int scnt, bcnt, fcnt, i;
2139     uint16 coverage, *bcoverage, *fcoverage, *sglyphs, *glyphs;
2140     FPST *fpst;
2141     struct fpst_rule *rule;
2142     (void)l; /* for -Wall */
2143     if ( justinuse==git_findnames )
2144 return;		/* Don't give names to these guys, they might not be unique */
2145     if ( getushort(ttf)!=1 )
2146 return;		/* Don't understand this format type */
2147 
2148     coverage = getushort(ttf);
2149     bcnt = getushort(ttf);
2150     bcoverage = galloc(bcnt*sizeof(uint16));
2151     for ( i = 0 ; i<bcnt; ++i )
2152 	bcoverage[i] = getushort(ttf);
2153     fcnt = getushort(ttf);
2154     fcoverage = galloc(fcnt*sizeof(uint16));
2155     for ( i = 0 ; i<fcnt; ++i )
2156 	fcoverage[i] = getushort(ttf);
2157     scnt = getushort(ttf);
2158     sglyphs = galloc((scnt+1)*sizeof(uint16));
2159     for ( i = 0 ; i<scnt; ++i )
2160 	if (( sglyphs[i] = getushort(ttf))>=info->glyph_cnt ) {
2161 	    LogError( _("Bad reverse contextual chaining substitution glyph: %d is not less than %d\n"),
2162 		    sglyphs[i], info->glyph_cnt );
2163 	    info->bad_ot = true;
2164 	    sglyphs[i] = 0;
2165 	}
2166     sglyphs[i] = 0xffff;
2167 
2168     if ( justinuse==git_justinuse ) {
2169 	for ( i = 0 ; i<scnt; ++i )
2170 	    info->inuse[sglyphs[i]] = 1;
2171     } else {
2172 	fpst = chunkalloc(sizeof(FPST));
2173 	fpst->type = pst_reversesub;
2174 	fpst->format = pst_reversecoverage;
2175 	fpst->subtable = subtable;
2176 	fpst->next = info->possub;
2177 	info->possub = fpst;
2178 	subtable->fpst = fpst;
2179 
2180 	fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
2181 	fpst->rule_cnt = 1;
2182 
2183 	rule->u.rcoverage.always1 = 1;
2184 	rule->u.rcoverage.bcnt = bcnt;
2185 	rule->u.rcoverage.fcnt = fcnt;
2186 	rule->u.rcoverage.ncovers = galloc(sizeof(char *));
2187 	rule->u.rcoverage.bcovers = galloc(bcnt*sizeof(char *));
2188 	rule->u.rcoverage.fcovers = galloc(fcnt*sizeof(char *));
2189 	rule->u.rcoverage.replacements = GlyphsToNames(info,sglyphs,false);
2190 	glyphs = getCoverageTable(ttf,stoffset+coverage,info);
2191 	rule->u.rcoverage.ncovers[0] = GlyphsToNames(info,glyphs,false);
2192 	free(glyphs);
2193 	for ( i=0; i<bcnt; ++i ) {
2194 	    glyphs = getCoverageTable(ttf,stoffset+bcoverage[i],info);
2195 	    rule->u.rcoverage.bcovers[i] = GlyphsToNames(info,glyphs,true);
2196 	    free(glyphs);
2197 	}
2198 	for ( i=0; i<fcnt; ++i ) {
2199 	    glyphs = getCoverageTable(ttf,stoffset+fcoverage[i],info);
2200 	    rule->u.rcoverage.fcovers[i] = GlyphsToNames(info,glyphs,true);
2201 	    free(glyphs);
2202 	}
2203 	rule->lookup_cnt = 0;		/* substitution lookups needed for reverse chaining */
2204     }
2205     free(sglyphs);
2206     free(fcoverage);
2207     free(bcoverage);
2208 }
2209 
readttfsizeparameters(FILE * ttf,int32 broken_pos,int32 correct_pos,struct ttfinfo * info)2210 static void readttfsizeparameters(FILE *ttf,int32 broken_pos,int32 correct_pos,
2211 	struct ttfinfo *info) {
2212     int32 here;
2213     /* Both of the two fonts I've seen that contain a 'size' feature */
2214     /*  have multiple features all of which point to the same parameter */
2215     /*  area. Odd. */
2216     /* When Adobe first released fonts containing the 'size' feature */
2217     /*  they did not follow the spec, and the offset to the size parameters */
2218     /*  was relative to the wrong location. They claim (Aug 2006) that */
2219     /*  this has been fixed. Be prepared to read either style of 'size' */
2220     /*  following the heuristics Adobe provides */
2221     int32 test[2];
2222     int i, nid;
2223 
2224     if ( info->last_size_pos==broken_pos || info->last_size_pos==correct_pos )
2225 return;
2226 
2227     if ( info->last_size_pos!=0 ) {
2228 	LogError( _("This font, %s, has multiple GPOS 'size' features. I'm not sure how to interpret that. I shall pick one arbitrarily.\n"),
2229 		info->fontname==NULL? _("<Untitled>") : info->fontname );
2230 	info->bad_ot = true;
2231 return;
2232     }
2233 
2234     test[0] = correct_pos; test[1] = broken_pos;
2235     here = ftell(ttf);
2236     for ( i=0; i<2; ++i ) {
2237 	fseek(ttf,test[i],SEEK_SET);
2238 	info->last_size_pos = test[i];
2239 	info->design_size = getushort(ttf);
2240 	if ( info->design_size==0 )
2241     continue;
2242 	info->fontstyle_id = getushort(ttf);
2243 	nid = getushort(ttf);
2244 	info->design_range_bottom = getushort(ttf);
2245 	info->design_range_top = getushort(ttf);
2246 	if ( info->fontstyle_id == 0 && nid==0 &&
2247 		info->design_range_bottom==0 && info->design_range_top==0 ) {
2248 	    /* Reasonable spec, only design size provided */
2249 	    info->fontstyle_name = NULL;
2250     break;
2251 	}
2252 	if ( info->design_size < info->design_range_bottom ||
2253 		info->design_size > info->design_range_top ||
2254 		info->design_range_bottom > info->design_range_top ||
2255 		nid<256 || nid>32767 )
2256     continue;
2257 	info->fontstyle_name = FindAllLangEntries(ttf,info,nid);
2258 	if ( info->fontstyle_name==NULL )
2259     continue;
2260 	else
2261     break;
2262     }
2263     if ( i==2 ) {
2264 	LogError(_("The 'size' feature does not seem to follow the standard,\nnor does it conform to Adobe's early misinterpretation of\nthe standard. I cannot parse it.\n") );
2265 	info->bad_ot = true;
2266 	info->design_size = info->design_range_bottom = info->design_range_top = info->fontstyle_id = 0;
2267 	info->fontstyle_name = NULL;
2268     } else if ( i==1 ) {
2269 	LogError(_("The 'size' feature of this font conforms to Adobe's early misinterpretation of the otf standard.\n") );
2270     }
2271     fseek(ttf,here,SEEK_SET);
2272 
2273 #if 0
2274  printf( "pos=%d  size=%g, range=(%g,%g] id=%d name=%d\n", pos,
2275 	 info->design_size/10.0, info->design_range_bottom/10.0, info->design_range_top/10.0,
2276 	 info->fontstyle_id, info->fontstyle_name );
2277 #endif
2278 }
2279 
readttfscripts(FILE * ttf,int32 pos,struct ttfinfo * info,int isgpos)2280 static struct scripts *readttfscripts(FILE *ttf,int32 pos, struct ttfinfo *info, int isgpos) {
2281     int i,j,k,cnt;
2282     int deflang, lcnt;
2283     struct scripts *scripts;
2284 
2285     if ( pos>=(int32)info->g_bounds ) {
2286 	LogError(_("Attempt to read script data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2287 	info->bad_ot = true;
2288 return( NULL );
2289     }
2290     fseek(ttf,pos,SEEK_SET);
2291     cnt = getushort(ttf);
2292     if ( cnt<=0 )
2293 return( NULL );
2294     else if ( cnt>1000 ) {
2295 	LogError( _("Too many scripts %d\n"), cnt );
2296 	info->bad_ot = true;
2297 return( NULL );
2298     }
2299 
2300     scripts = gcalloc(cnt+1,sizeof(struct scripts));
2301     for ( i=0; i<cnt; ++i ) {
2302 	scripts[i].tag = getlong(ttf);
2303 	scripts[i].offset = getushort(ttf);
2304     }
2305     for ( i=0; i<cnt; ++i ) {
2306 	fseek(ttf,pos+scripts[i].offset,SEEK_SET);
2307 	deflang = getushort(ttf);
2308 	lcnt = getushort(ttf);
2309 	lcnt += (deflang!=0);
2310 	scripts[i].langcnt = lcnt;
2311 	scripts[i].languages = gcalloc(lcnt+1,sizeof(struct language));
2312 	j = 0;
2313 	if ( deflang!=0 ) {
2314 	    scripts[i].languages[0].tag = CHR('d','f','l','t');
2315 	    scripts[i].languages[0].offset = deflang+scripts[i].offset;
2316 	    ++j;
2317 	}
2318 	for ( ; j<lcnt; ++j ) {
2319 	    scripts[i].languages[j].tag = getlong(ttf);
2320 	    scripts[i].languages[j].offset = scripts[i].offset+getushort(ttf);
2321 	}
2322 	for ( j=0; j<lcnt; ++j ) {
2323 	    if ( pos+scripts[i].languages[j].offset>=info->g_bounds ) {
2324 		LogError(_("Attempt to read script data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2325 		info->bad_ot = true;
2326 return( NULL );
2327 	    }
2328 	    fseek(ttf,pos+scripts[i].languages[j].offset,SEEK_SET);
2329 	    (void) getushort(ttf);	/* lookup ordering table undefined */
2330 	    scripts[i].languages[j].req = getushort(ttf);
2331 	    scripts[i].languages[j].fcnt = getushort(ttf);
2332 	    if ( feof(ttf)) {
2333 		LogError(_("End of file when reading scripts in %s table"), isgpos ? "GPOS" : "GSUB" );
2334 		info->bad_ot = true;
2335 return( NULL );
2336 	    }
2337 	    scripts[i].languages[j].features = galloc(scripts[i].languages[j].fcnt*sizeof(uint16));
2338 	    for ( k=0; k<scripts[i].languages[j].fcnt; ++k )
2339 		scripts[i].languages[j].features[k] = getushort(ttf);
2340 	}
2341     }
2342 
2343     if ( feof(ttf)) {
2344 	LogError(_("End of file in %s table"), isgpos ? "GPOS" : "GSUB" );
2345 	info->bad_ot = true;
2346 return( NULL );
2347     }
2348 
2349 return( scripts );
2350 }
2351 
readttffeatures(FILE * ttf,int32 pos,int isgpos,struct ttfinfo * info)2352 static struct feature *readttffeatures(FILE *ttf,int32 pos,int isgpos, struct ttfinfo *info) {
2353     /* read the features table returning an array containing all interesting */
2354     /*  features */
2355     int cnt;
2356     int i,j;
2357     struct feature *features;
2358     int parameters;
2359 
2360     if ( pos>=(int32)info->g_bounds ) {
2361 	LogError(_("Attempt to read feature data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2362 	info->bad_ot = true;
2363 return( NULL );
2364     }
2365     fseek(ttf,pos,SEEK_SET);
2366     info->feature_cnt = cnt = getushort(ttf);
2367     if ( cnt<=0 )
2368 return( NULL );
2369     else if ( cnt>1000 ) {
2370 	LogError( _("Too many features %d\n"), cnt );
2371 	info->bad_ot = true;
2372 return( NULL );
2373     }
2374 
2375     features = gcalloc(cnt+1,sizeof(struct feature));
2376     for ( i=0; i<cnt; ++i ) {
2377 	features[i].tag = getlong(ttf);
2378 	features[i].offset = getushort(ttf);
2379     }
2380 
2381     for ( i=0; i<cnt; ++i ) {
2382 	if ( pos+features[i].offset>=info->g_bounds ) {
2383 	    LogError(_("Attempt to read feature data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2384 	    info->bad_ot = true;
2385 return( NULL );
2386 	}
2387 	fseek(ttf,pos+features[i].offset,SEEK_SET);
2388 	parameters = getushort(ttf);
2389 	if ( features[i].tag==CHR('s','i','z','e') && parameters!=0 && !feof(ttf))
2390 	    readttfsizeparameters(ttf,pos+parameters,
2391 		    pos+parameters+features[i].offset,info);
2392 	features[i].lcnt = getushort(ttf);
2393 	if ( feof(ttf) ) {
2394 	    LogError(_("End of file when reading features in %s table"), isgpos ? "GPOS" : "GSUB" );
2395 	    info->bad_ot = true;
2396 return( NULL );
2397 	}
2398 	features[i].lookups = galloc(features[i].lcnt*sizeof(uint16));
2399 	for ( j=0; j<features[i].lcnt; ++j )
2400 	    features[i].lookups[j] = getushort(ttf);
2401     }
2402 
2403 return( features );
2404 }
2405 
readttflookups(FILE * ttf,int32 pos,struct ttfinfo * info,int isgpos)2406 static struct lookup *readttflookups(FILE *ttf,int32 pos, struct ttfinfo *info, int isgpos) {
2407     int cnt,i,j;
2408     struct lookup *lookups;
2409     OTLookup *otlookup, *last=NULL;
2410     struct lookup_subtable *st;
2411 
2412     if ( pos>=(int32)info->g_bounds ) {
2413 	LogError(_("Attempt to read lookup data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2414 	info->bad_ot = true;
2415 return( NULL );
2416     }
2417 
2418     fseek(ttf,pos,SEEK_SET);
2419     info->lookup_cnt = cnt = getushort(ttf);
2420     info->cur_lookups = NULL;
2421     if ( cnt<=0 )
2422 return( NULL );
2423     else if ( cnt>1000 ) {
2424 	LogError( _("Too many lookups %d\n"), cnt );
2425 	info->bad_ot = true;
2426 return( NULL );
2427     }
2428 
2429     lookups = gcalloc(cnt+1,sizeof(struct lookup));
2430     for ( i=0; i<cnt; ++i )
2431 	lookups[i].offset = getushort(ttf);
2432     for ( i=0; i<cnt; ++i ) {
2433 	if ( pos+lookups[i].offset>=info->g_bounds ) {
2434 	    LogError(_("Attempt to read lookup data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2435 	    info->bad_ot = true;
2436 return( NULL );
2437 	}
2438 	fseek(ttf,pos+lookups[i].offset,SEEK_SET);
2439 	lookups[i].type = getushort(ttf);
2440 	lookups[i].flags = getushort(ttf);
2441 	lookups[i].subtabcnt = getushort(ttf);
2442 	lookups[i].subtab_offsets = galloc(lookups[i].subtabcnt*sizeof(int32));
2443 	for ( j=0; j<lookups[i].subtabcnt; ++j )
2444 	    lookups[i].subtab_offsets[j] = pos+lookups[i].offset+getushort(ttf);
2445 
2446 	lookups[i].otlookup = otlookup = chunkalloc(sizeof(OTLookup));
2447 	otlookup->lookup_index = i;
2448 	if ( last==NULL )
2449 	    info->cur_lookups = otlookup;
2450 	else
2451 	    last->next = otlookup;
2452 	last = otlookup;
2453 	otlookup->lookup_type = (isgpos<<8) | lookups[i].type;
2454 	otlookup->lookup_flags = lookups[i].flags;
2455 	otlookup->lookup_index = i;
2456 	if ( feof(ttf) ) {
2457 	    LogError(_("End of file when reading lookups in %s table"), isgpos ? "GPOS" : "GSUB" );
2458 	    info->bad_ot = true;
2459 return( NULL );
2460 	}
2461 	for ( j=0; j<lookups[i].subtabcnt; ++j ) {
2462 	    st = chunkalloc(sizeof(struct lookup_subtable));
2463 	    st->next = otlookup->subtables;
2464 	    st->lookup = otlookup;
2465 	    otlookup->subtables = st;
2466 	}
2467     }
2468     if ( isgpos )
2469 	info->gpos_lookups = info->cur_lookups;
2470     else
2471 	info->gsub_lookups = info->cur_lookups;
2472 return( lookups );
2473 }
2474 
tagLookupsWithFeature(uint32 script_tag,uint32 lang_tag,int required_feature,struct feature * feature,struct lookup * lookups,struct ttfinfo * info)2475 static void tagLookupsWithFeature(uint32 script_tag,uint32 lang_tag,
2476 	int required_feature, struct feature *feature, struct lookup *lookups,
2477 	struct ttfinfo *info) {
2478     uint32 feature_tag = required_feature ? REQUIRED_FEATURE : feature->tag;
2479     int i;
2480     OTLookup *otlookup;
2481     FeatureScriptLangList *fl;
2482 
2483     /* The otf docs are ambiguous as to the capitalization of the default */
2484     /*  script. The capitalized version is correct (uncapitalized is used for languages) */
2485     if ( script_tag == DEFAULT_LANG )
2486 	script_tag = DEFAULT_SCRIPT;
2487 
2488     for ( i=0; i < feature->lcnt; ++i ) {
2489 	if ( feature->lookups[i]>=info->lookup_cnt ) {
2490 	    LogError( _("Lookup out of bounds in feature table.\n") );
2491 	    info->bad_ot = true;
2492 	} else {
2493 	    otlookup = lookups[feature->lookups[i]].otlookup;
2494 	    for ( fl = otlookup->features; fl!=NULL && fl->featuretag!=feature_tag; fl=fl->next );
2495 	    if ( fl==NULL ) {
2496 		fl = chunkalloc(sizeof(FeatureScriptLangList));
2497 		fl->featuretag = feature_tag;
2498 		fl->next = otlookup->features;
2499 		otlookup->features = fl;
2500 	    }
2501 	    FListAppendScriptLang(fl,script_tag,lang_tag);
2502 	}
2503     }
2504 }
2505 
tagLookupsWithScript(struct scripts * scripts,struct feature * features,struct lookup * lookups,struct ttfinfo * info)2506 static void tagLookupsWithScript(struct scripts *scripts,
2507 	struct feature *features, struct lookup *lookups,struct ttfinfo *info ) {
2508     int i,j;
2509     struct scripts *s;
2510     struct language *lang;
2511     struct lookup *l;
2512 
2513     if ( scripts==NULL || features==NULL )
2514 return;		/* Legal, I'd guess, but not very interesting. Perhaps all lookups are controlled by the JSTF table or something */
2515 
2516     /* First tag every lookup with all script, lang, feature combinations that*/
2517     /*  invoke it */
2518     for ( s=scripts; s->tag!=0; ++s ) {
2519 	for ( lang=s->languages, i=0; i<s->langcnt; ++i, ++lang ) {
2520 	    if ( lang->req==0xffff )
2521 		/* Do Nothing */;
2522 	    else if ( lang->req>= info->feature_cnt ) {
2523 		LogError( _("Required feature out of bounds in script table.\n") );
2524 		info->bad_ot = true;
2525 	    } else
2526 		tagLookupsWithFeature(s->tag,lang->tag,true,&features[lang->req],
2527 			lookups,info);
2528 	    for ( j=0; j<lang->fcnt; ++j ) {
2529 		if ( lang->features[j]>=info->feature_cnt ) {
2530 		    LogError( _("Feature out of bounds in script table.\n") );
2531 		    info->bad_ot = true;
2532 		} else
2533 		    tagLookupsWithFeature(s->tag,lang->tag,false,&features[lang->features[j]],
2534 			    lookups,info);
2535 	    }
2536 	}
2537     }
2538 
2539     /* The scripts got added backwards so reverse to put them in */
2540     /*  alphabetic order again */
2541     for ( l=lookups, i=0; l->offset!=0; ++l, ++i ) {
2542 	OTLookup *otl = l->otlookup;
2543 	FeatureScriptLangList *fl;
2544 	struct scriptlanglist *sl, *next, *prev;
2545 	for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
2546 	    prev = NULL;
2547 	    for ( sl=fl->scripts; sl!=NULL; sl = next ) {
2548 		next = sl->next;
2549 		sl->next = prev;
2550 		prev = sl;
2551 	    }
2552 	    fl->scripts = prev;
2553 	}
2554     }
2555 }
2556 
gposExtensionSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,struct lookup * alllooks)2557 static void gposExtensionSubTable(FILE *ttf, int stoffset,
2558 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
2559 	struct lookup *alllooks) {
2560     uint32 base = ftell(ttf), st, offset;
2561     int lu_type;
2562     (void)stoffset; /* for -Wall */
2563     /* Format = */ getushort(ttf);
2564     lu_type = getushort(ttf);
2565     offset = getlong(ttf);
2566 
2567     l->otlookup->lookup_type = 0x100|lu_type;
2568 
2569     fseek(ttf,st = base+offset,SEEK_SET);
2570     switch ( lu_type ) {
2571       case 1:
2572 	gposSimplePos(ttf,st,info,l,subtable);
2573       break;
2574       case 2:
2575 	gposKernSubTable(ttf,st,info,l,subtable);
2576       break;
2577       case 3:
2578 	gposCursiveSubTable(ttf,st,info,l,subtable);
2579       break;
2580       case 4: case 5: case 6:
2581 	gposMarkSubTable(ttf,st,info,l,subtable);
2582       break;
2583       case 7:
2584 	gposContextSubTable(ttf,st,info,l,subtable,alllooks);
2585       break;
2586       case 8:
2587 	gposChainingSubTable(ttf,st,info,l,subtable,alllooks);
2588       break;
2589       case 9:
2590 	LogError( _("This font is erroneous: it has a GPOS extension subtable that points to\nanother extension sub-table.\n") );
2591 	info->bad_ot = true;
2592       break;
2593 /* Any cases added here also need to go in the gposLookupSwitch */
2594       default:
2595 	LogError( _("Unknown GPOS sub-table type: %d\n"), lu_type );
2596 	info->bad_ot = true;
2597       break;
2598     }
2599     if ( ftell(ttf)>info->gpos_start+info->gpos_length ) {
2600 	LogError( _("Subtable extends beyond end of GPOS table\n") );
2601 	info->bad_ot = true;
2602     }
2603 }
2604 
gsubExtensionSubTable(FILE * ttf,int stoffset,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks)2605 static void gsubExtensionSubTable(FILE *ttf, int stoffset,
2606 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2607 	struct lookup *alllooks) {
2608     uint32 base = ftell(ttf), st, offset;
2609     int lu_type;
2610     (void)stoffset; /* for -Wall */
2611     /* Format = */ getushort(ttf);
2612     lu_type = getushort(ttf);
2613     offset = getlong(ttf);
2614 
2615     l->otlookup->lookup_type = lu_type;
2616 
2617     fseek(ttf,st = base+offset,SEEK_SET);
2618     switch ( lu_type ) {
2619       case 1:
2620 	gsubSimpleSubTable(ttf,st,info,l,subtable,justinuse);
2621       break;
2622       case 2: case 3:	/* Multiple and alternate have same format, different semantics */
2623 	gsubMultipleSubTable(ttf,st,info,l,subtable,justinuse);
2624       break;
2625       case 4:
2626 	gsubLigatureSubTable(ttf,st,info,l,subtable,justinuse);
2627       break;
2628       case 5:
2629 	gsubContextSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2630       break;
2631       case 6:
2632 	gsubChainingSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2633       break;
2634       case 7:
2635 	LogError( _("This font is erroneous: it has a GSUB extension subtable that points to\nanother extension sub-table.\n") );
2636 	info->bad_ot = true;
2637       break;
2638       case 8:
2639 	gsubReverseChainSubTable(ttf,st,info,l,subtable,justinuse);
2640       break;
2641 /* Any cases added here also need to go in the gsubLookupSwitch */
2642       default:
2643 	LogError( _("Unknown GSUB sub-table type: %d\n"), lu_type );
2644 	info->bad_ot = true;
2645       break;
2646     }
2647     if ( ftell(ttf)>info->gsub_start+info->gsub_length ) {
2648 	LogError( _("Subtable extends beyond end of GSUB table\n") );
2649 	info->bad_ot = true;
2650     }
2651 }
2652 
gposLookupSwitch(FILE * ttf,int st,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,struct lookup * alllooks)2653 static void gposLookupSwitch(FILE *ttf, int st,
2654 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
2655 	struct lookup *alllooks) {
2656 
2657     switch ( l->type | 0x100 ) {
2658       case gpos_single:
2659 	gposSimplePos(ttf,st,info,l,subtable);
2660       break;
2661       case gpos_pair:
2662 	gposKernSubTable(ttf,st,info,l,subtable);
2663       break;
2664       case gpos_cursive:
2665 	gposCursiveSubTable(ttf,st,info,l,subtable);
2666       break;
2667       case gpos_mark2base: case gpos_mark2ligature: case gpos_mark2mark:
2668 	gposMarkSubTable(ttf,st,info,l,subtable);
2669       break;
2670       case gpos_context:
2671 	gposContextSubTable(ttf,st,info,l,subtable,alllooks);
2672       break;
2673       case gpos_contextchain:
2674 	gposChainingSubTable(ttf,st,info,l,subtable,alllooks);
2675       break;
2676       case 0x109:
2677 	gposExtensionSubTable(ttf,st,info,l,subtable,alllooks);
2678       break;
2679 /* Any cases added here also need to go in the gposExtensionSubTable */
2680       default:
2681 	LogError( _("Unknown GPOS sub-table type: %d\n"), l->otlookup->lookup_type );
2682 	info->bad_ot = true;
2683       break;
2684     }
2685     if ( ftell(ttf)>info->gpos_start+info->gpos_length ) {
2686 	LogError( _("Subtable extends beyond end of GPOS table\n") );
2687 	info->bad_ot = true;
2688     }
2689 }
2690 
gsubLookupSwitch(FILE * ttf,int st,struct ttfinfo * info,struct lookup * l,struct lookup_subtable * subtable,int justinuse,struct lookup * alllooks)2691 static void gsubLookupSwitch(FILE *ttf, int st,
2692 	struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2693 	struct lookup *alllooks) {
2694 
2695     switch ( l->type ) {
2696       case gsub_single:
2697 	gsubSimpleSubTable(ttf,st,info,l,subtable,justinuse);
2698       break;
2699       case gsub_multiple: case gsub_alternate:	/* Multiple and alternate have same format, different semantics */
2700 	gsubMultipleSubTable(ttf,st,info,l,subtable,justinuse);
2701       break;
2702       case gsub_ligature:
2703 	gsubLigatureSubTable(ttf,st,info,l,subtable,justinuse);
2704       break;
2705       case gsub_context:
2706 	gsubContextSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2707       break;
2708       case gsub_contextchain:
2709 	gsubChainingSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2710       break;
2711       case 7:
2712 	gsubExtensionSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2713       break;
2714       case gsub_reversecchain:
2715 	gsubReverseChainSubTable(ttf,st,info,l,subtable,justinuse);
2716       break;
2717 /* Any cases added here also need to go in the gsubExtensionSubTable */
2718       default:
2719 	LogError( _("Unknown GSUB sub-table type: %d\n"), l->otlookup->lookup_type );
2720 	info->bad_ot = true;
2721       break;
2722     }
2723     if ( ftell(ttf)>info->g_bounds ) {
2724 	LogError( _("Subtable extends beyond end of GSUB table\n" ));
2725 	info->bad_ot = true;
2726     }
2727 }
2728 
ScriptsFree(struct scripts * scripts)2729 static void ScriptsFree(struct scripts *scripts) {
2730     int i,j;
2731 
2732     if ( scripts==NULL )
2733 return;
2734     for ( i=0; scripts[i].offset!=0 ; ++i ) {
2735 	for ( j=0; j<scripts[i].langcnt; ++j )
2736 	    free( scripts[i].languages[j].features);
2737 	free(scripts[i].languages);
2738     }
2739     free(scripts);
2740 }
2741 
FeaturesFree(struct feature * features)2742 static void FeaturesFree(struct feature *features) {
2743     int i;
2744 
2745     if ( features==NULL )
2746 return;
2747     for ( i=0; features[i].offset!=0 ; ++i )
2748 	free(features[i].lookups);
2749     free(features);
2750 }
2751 
LookupsFree(struct lookup * lookups)2752 static void LookupsFree(struct lookup *lookups) {
2753     int i;
2754 
2755     for ( i=0; lookups[i].offset!=0 ; ++i ) {
2756 	free( lookups[i].subtab_offsets );
2757     }
2758     free(lookups);
2759 }
2760 
ProcessGPOSGSUB(FILE * ttf,struct ttfinfo * info,int gpos,int inusetype)2761 static void ProcessGPOSGSUB(FILE *ttf,struct ttfinfo *info,int gpos,int inusetype) {
2762     int k;
2763     int32 base, lookup_start, st;
2764     int32 script_off, feature_off;
2765     struct scripts *scripts;
2766     struct feature *features;
2767     struct lookup *lookups, *l;
2768     struct lookup_subtable *subtable;
2769 
2770     if ( gpos ) {
2771 	base = info->gpos_start;
2772 	info->g_bounds = base + info->gpos_length;
2773     } else {
2774 	base = info->gsub_start;
2775 	info->g_bounds = base + info->gsub_length;
2776     }
2777     fseek(ttf,base,SEEK_SET);
2778     /* version = */ getlong(ttf);
2779     script_off = getushort(ttf);
2780     feature_off = getushort(ttf);
2781     lookup_start = base+getushort(ttf);
2782 
2783     scripts = readttfscripts(ttf,base+script_off,info,gpos);
2784     features = readttffeatures(ttf,base+feature_off,gpos,info);
2785     /* It is legal to have lookups with no features or scripts */
2786     /* For example if all the lookups were controlled by the JSTF table */
2787     lookups = readttflookups(ttf,lookup_start,info,gpos);
2788     if ( lookups==NULL ) {
2789 	ScriptsFree(scripts);
2790 	FeaturesFree(features);
2791 return;
2792     }
2793     tagLookupsWithScript(scripts,features,lookups,info);
2794     ScriptsFree(scripts); scripts = NULL;
2795     FeaturesFree(features); features = NULL;
2796 
2797     for ( l = lookups; l->offset!=0; ++l ) {
2798 	for ( k=0, subtable=l->otlookup->subtables; k<l->subtabcnt; ++k, subtable=subtable->next ) {
2799 	    st = l->subtab_offsets[k];
2800 	    fseek(ttf,st,SEEK_SET);
2801 	    if ( gpos ) {
2802 		gposLookupSwitch(ttf,st,info,l,subtable,lookups);
2803 	    } else {
2804 		gsubLookupSwitch(ttf,st,info,l,subtable,inusetype,lookups);
2805 	    }
2806 	}
2807     }
2808 
2809     /* Then generate some user-friendly names for the all the lookups */
2810     if ( inusetype==git_normal )
2811 	for ( l=lookups; l->offset!=0; ++l )
2812 	    NameOTLookup(l->otlookup,NULL);
2813 
2814     LookupsFree(lookups);
2815     if ( inusetype!=git_normal && !gpos ) {
2816 	OTLookupListFree(info->gsub_lookups);
2817 	info->gsub_lookups = info->cur_lookups = NULL;
2818     }
2819 }
2820 
readttfgsubUsed(FILE * ttf,struct ttfinfo * info)2821 void readttfgsubUsed(FILE *ttf,struct ttfinfo *info) {
2822     ProcessGPOSGSUB(ttf,info,false,git_justinuse);
2823     info->g_bounds = 0;
2824 }
2825 
GuessNamesFromGSUB(FILE * ttf,struct ttfinfo * info)2826 void GuessNamesFromGSUB(FILE *ttf,struct ttfinfo *info) {
2827     ProcessGPOSGSUB(ttf,info,false,git_findnames);
2828     info->g_bounds = 0;
2829 }
2830 
readttfgpossub(FILE * ttf,struct ttfinfo * info,int gpos)2831 void readttfgpossub(FILE *ttf,struct ttfinfo *info,int gpos) {
2832     ProcessGPOSGSUB(ttf,info,gpos,git_normal);
2833     info->g_bounds = 0;
2834 }
2835 
readttfgdef(FILE * ttf,struct ttfinfo * info)2836 void readttfgdef(FILE *ttf,struct ttfinfo *info) {
2837     int lclo, gclass, mac;
2838     int coverage, cnt, i,j, format;
2839     uint16 *glyphs, *lc_offsets, *offsets;
2840     uint32 caret_base;
2841     PST *pst;
2842     SplineChar *sc;
2843 
2844     fseek(ttf,info->gdef_start,SEEK_SET);
2845     if ( getlong(ttf)!=0x00010000 )
2846 return;
2847     info->g_bounds = info->gdef_start + info->gdef_length;
2848     gclass = getushort(ttf);
2849     /* attach list = */ getushort(ttf);
2850     lclo = getushort(ttf);		/* ligature caret list */
2851     mac = getushort(ttf);		/* mark attach class */
2852 
2853     if ( gclass!=0 ) {
2854 	uint16 *gclasses = getClassDefTable(ttf,info->gdef_start+gclass, info);
2855 	for ( i=0; i<info->glyph_cnt; ++i )
2856 	    if ( info->chars[i]!=NULL && gclasses[i]!=0 )
2857 		info->chars[i]->glyph_class = gclasses[i]+1;
2858 	free(gclasses);
2859     }
2860 
2861     if ( mac!=0 ) {
2862 	uint16 *mclasses = getClassDefTable(ttf,info->gdef_start+mac, info);
2863 	const char *format_spec = _("MarkClass-%d");
2864 	info->mark_class_cnt = ClassFindCnt(mclasses,info->glyph_cnt);
2865 	info->mark_classes = ClassToNames(info,info->mark_class_cnt,mclasses,info->glyph_cnt);
2866 	info->mark_class_names = galloc(info->mark_class_cnt*sizeof(char *));
2867 	info->mark_class_names[0] = NULL;
2868 	for ( i=1; i<info->mark_class_cnt; ++i ) {
2869 	    info->mark_class_names[i] = galloc((strlen(format_spec)+10));
2870 	    sprintf( info->mark_class_names[i], format_spec, i );
2871 	}
2872 	free(mclasses);
2873     }
2874 
2875     if ( lclo!=0 ) {
2876 	lclo += info->gdef_start;
2877 	fseek(ttf,lclo,SEEK_SET);
2878 	coverage = getushort(ttf);
2879 	cnt = getushort(ttf);
2880 	if ( cnt==0 )
2881 return;
2882 	lc_offsets = galloc(cnt*sizeof(uint16));
2883 	for ( i=0; i<cnt; ++i )
2884 	    lc_offsets[i]=getushort(ttf);
2885 	glyphs = getCoverageTable(ttf,lclo+coverage,info);
2886 	if ( glyphs==NULL )
2887 return;
2888 	for ( i=0; i<cnt; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
2889 	    fseek(ttf,lclo+lc_offsets[i],SEEK_SET);
2890 	    sc = info->chars[glyphs[i]];
2891 	    for ( pst=sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
2892 	    if ( pst==NULL ) {
2893 		pst = chunkalloc(sizeof(PST));
2894 		pst->next = sc->possub;
2895 		sc->possub = pst;
2896 		pst->type = pst_lcaret;
2897 		pst->subtable = NULL;
2898 		sc->lig_caret_cnt_fixed = true;
2899 	    }
2900 	    caret_base = ftell(ttf);
2901 	    pst->u.lcaret.cnt = getushort(ttf);
2902 	    if ( pst->u.lcaret.carets!=NULL ) free(pst->u.lcaret.carets);
2903 	    offsets = galloc(pst->u.lcaret.cnt*sizeof(uint16));
2904 	    for ( j=0; j<pst->u.lcaret.cnt; ++j )
2905 		offsets[j] = getushort(ttf);
2906 	    pst->u.lcaret.carets = galloc(pst->u.lcaret.cnt*sizeof(int16));
2907 	    for ( j=0; j<pst->u.lcaret.cnt; ++j ) {
2908 		fseek(ttf,caret_base+offsets[j],SEEK_SET);
2909 		format=getushort(ttf);
2910 		if ( format==1 ) {
2911 		    pst->u.lcaret.carets[j] = getushort(ttf);
2912 		} else if ( format==2 ) {
2913 		    pst->u.lcaret.carets[j] = 0;
2914 		    /* point = */ getushort(ttf);
2915 		} else if ( format==3 ) {
2916 		    pst->u.lcaret.carets[j] = getushort(ttf);
2917 		    /* in device table = */ getushort(ttf);
2918 		} else {
2919 		    LogError( _("!!!! Unknown caret format %d !!!!\n"), format );
2920 		    info->bad_ot = true;
2921 		}
2922 	    }
2923 	    free(offsets);
2924 	}
2925 	free(lc_offsets);
2926 	free(glyphs);
2927     }
2928     info->g_bounds = 0;
2929 }
2930 
OTLAppend(struct ttfinfo * info,OTLookup * otl,int gpos)2931 static void OTLAppend(struct ttfinfo *info,OTLookup *otl,int gpos) {
2932     OTLookup *prev;
2933     int pos=0;
2934 
2935     if ( gpos && info->gpos_lookups == NULL )
2936 	info->gpos_lookups = otl;
2937     else if ( !gpos && info->gsub_lookups == NULL )
2938 	info->gsub_lookups = otl;
2939     else {
2940 	prev = gpos ? info->gpos_lookups : info->gsub_lookups;
2941 	pos = 1;
2942 	while ( prev->next!=NULL ) {
2943 	    prev = prev->next;
2944 	    ++pos;
2945 	}
2946 	prev->next = otl;
2947     }
2948     otl->lookup_index = pos;
2949 }
2950 
OTLRemove(struct ttfinfo * info,OTLookup * otl,int gpos)2951 static void OTLRemove(struct ttfinfo *info,OTLookup *otl,int gpos) {
2952     /* Remove the most recent lookup. We got bad data and can't use it */
2953     OTLookup *prev, **base;
2954 
2955     base = gpos ? &info->gpos_lookups : &info->gsub_lookups;
2956     if ( *base==otl )
2957 	*base = NULL;
2958     else if ( *base!=NULL ) {
2959 	for ( prev = *base; prev->next!=NULL && prev->next!=otl; prev = prev->next );
2960 	prev->next = NULL;
2961     }
2962     OTLookupFree(otl);
2963 }
2964 
InfoNameOTLookup(OTLookup * otl,struct ttfinfo * info)2965 static void InfoNameOTLookup(OTLookup *otl,struct ttfinfo *info) {
2966     SplineFont sf;
2967 
2968     memset(&sf,0,sizeof(sf));
2969     NameOTLookup(otl,&sf);
2970 }
2971 
2972 /* Apple's docs imply that kerning info is always provided left to right, even*/
2973 /*  for right to left scripts. My guess is that their docs are wrong, as they */
2974 /*  often are, but if that be so then we need code in here to reverse */
2975 /*  the order of the characters for right to left since pfaedit's convention */
2976 /*  is to follow writing order rather than to go left to right */
readttfkerns(FILE * ttf,struct ttfinfo * info)2977 void readttfkerns(FILE *ttf,struct ttfinfo *info) {
2978     int tabcnt, len, coverage,i,j, npairs, version, format, flags_good, tab;
2979     int left, right, offset, array, rowWidth;
2980     int header_size;
2981     KernPair *kp;
2982     KernClass *kc;
2983     uint32 begin_table;
2984     uint16 *class1, *class2;
2985     int isv;
2986     OTLookup *otl;
2987 
2988     fseek(ttf,info->kern_start,SEEK_SET);
2989     version = getushort(ttf);
2990     tabcnt = getushort(ttf);
2991     if ( version!=0 ) {
2992 	LogError(_("Invalid or unsupported version (0x%x) for 'kern' table"), version );
2993 	info->bad_gx = true;
2994 return;
2995     }
2996     for ( tab=0; tab<tabcnt; ++tab ) {
2997 	begin_table = ftell(ttf);
2998 	/* version = */ getushort(ttf);
2999 	len = getushort(ttf);
3000 	coverage = getushort(ttf);
3001 	format = coverage>>8;
3002 	flags_good = ((coverage&7)<=1);
3003 	isv = !(coverage&1);
3004 	header_size = 6;
3005 	otl = NULL;
3006 	if ( flags_good ) {
3007 	    otl = chunkalloc(sizeof(OTLookup));
3008 	    otl->lookup_type = gpos_pair;
3009 	    otl->subtables = chunkalloc(sizeof(struct lookup_subtable));
3010 	    otl->subtables->lookup = otl;
3011 	    otl->subtables->per_glyph_pst_or_kern = true;
3012 	    otl->subtables->vertical_kerning = isv;
3013 	    otl->features = chunkalloc(sizeof(FeatureScriptLangList));
3014 	    if (isv)
3015 		otl->features->featuretag = CHR('v','k','r','n');
3016 	    else
3017 		otl->features->featuretag = CHR('k','e','r','n');
3018 	    OTLAppend(info,otl,true);
3019 	}
3020 	if ( flags_good && format==0 ) {
3021 	    /* format 0, horizontal kerning data (as pairs) not perpendicular */
3022 	    SplineChar **chars = info->chars;
3023 	    npairs = getushort(ttf);
3024 	    if ( len-14 != 6*npairs || npairs>10920 ) {
3025 		LogError( _("In the 'kern' table, a subtable's length does not match the number of kerning pairs.") );
3026 		info->bad_gx = true;
3027 	    }
3028 	    /* searchRange = */ getushort(ttf);
3029 	    /* entrySelector = */ getushort(ttf);
3030 	    /* rangeShift = */ getushort(ttf);
3031 	    otl->subtables[0].per_glyph_pst_or_kern = true;
3032 	    for ( j=0; j<npairs; ++j ) {
3033 		left = getushort(ttf);
3034 		right = getushort(ttf);
3035 		offset = (short) getushort(ttf);
3036 		if ( left<0 || right<0 ) {
3037 		    /* We've seen such buggy fonts... */
3038 		    LogError( _("Bad kern pair: glyphs %d & %d mustn't be negative\n"),
3039 			    left, right );
3040 		    info->bad_gx = true;
3041 		} else if ( left>=info->glyph_cnt || right>=info->glyph_cnt ) {
3042 		    /* Holes happen when reading ttc files. They are probably ok */
3043 		    LogError( _("Bad kern pair: glyphs %d & %d must be less than %d\n"),
3044 			    left, right, info->glyph_cnt );
3045 		    info->bad_gx = true;
3046 		} else if (chars[left]==NULL || chars[right]==NULL ) {
3047                     /* Shouldn't happen. */
3048 		    LogError( _("Bad kern pair: glyphs at %d & %d are null\n"),
3049 			    left, right);
3050 		    info->bad_gx = true;
3051 		} else {
3052 		    kp = chunkalloc(sizeof(KernPair));
3053 		    kp->sc = chars[right];
3054 		    kp->off = offset;
3055 		    kp->subtable = otl->subtables;
3056 		    FListsAppendScriptLang(otl->features,SCScriptFromUnicode(chars[left]),
3057 			    DEFAULT_LANG);
3058 		    if ( isv ) {
3059 			kp->next = chars[left]->vkerns;
3060 			chars[left]->vkerns = kp;
3061 		    } else {
3062 			kp->next = chars[left]->kerns;
3063 			chars[left]->kerns = kp;
3064 		    }
3065 		}
3066 	    }
3067 	    InfoNameOTLookup(otl,info);
3068 	} else if ( flags_good && (format==2 || format==3 )) {
3069 	    /* two class based formats */
3070 	    KernClass **khead, **klast;
3071 	    if ( isv ) {
3072 		khead = &info->vkhead;
3073 		klast = &info->vklast;
3074 	    } else {
3075 		khead = &info->khead;
3076 		klast = &info->klast;
3077 	    }
3078 	    if ( *khead==NULL )
3079 		*khead = kc = chunkalloc(sizeof(KernClass));
3080 	    else
3081 		kc = (*klast)->next = chunkalloc(sizeof(KernClass));
3082 	    *klast = kc;
3083 	    if ( format==2 ) {
3084 		rowWidth = getushort(ttf);
3085 		left = getushort(ttf);
3086 		right = getushort(ttf);
3087 		array = getushort(ttf);
3088 		kc->second_cnt = rowWidth/sizeof(uint16);
3089 		class1 = getAppleClassTable(ttf, begin_table+left, info->glyph_cnt, array, rowWidth, info );
3090 		class2 = getAppleClassTable(ttf, begin_table+right, info->glyph_cnt, 0, sizeof(uint16), info );
3091 		for ( i=0; i<info->glyph_cnt; ++i )
3092 		    if ( class1[i]>kc->first_cnt )
3093 			kc->first_cnt = class1[i];
3094 		++ kc->first_cnt;
3095 		kc->offsets = galloc(kc->first_cnt*kc->second_cnt*sizeof(int16));
3096 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3097 		kc->adjusts = gcalloc(kc->first_cnt*kc->second_cnt,sizeof(DeviceTable));
3098 #endif
3099 		fseek(ttf,begin_table+array,SEEK_SET);
3100 		for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i )
3101 		    kc->offsets[i] = getushort(ttf);
3102 	    } else {
3103 		/* format 3, horizontal kerning data (as classes limited to 256 entries) */
3104 		/*  OpenType's spec doesn't document this */
3105 		int gc, kv, flags;
3106 		int16 *kvs;
3107 		gc = getushort(ttf);
3108 		kv = getc(ttf);
3109 		kc->first_cnt = getc(ttf);
3110 		kc->second_cnt = getc(ttf);
3111 		flags = getc(ttf);
3112 		if ( gc>info->glyph_cnt ) {
3113 		    LogError( _("Kerning subtable 3 says the glyph count is %d, but maxp says %d\n"),
3114 			    gc, info->glyph_cnt );
3115 		    info->bad_gx = true;
3116 		}
3117 		class1 = gcalloc(gc>info->glyph_cnt?gc:info->glyph_cnt,sizeof(uint16));
3118 		class2 = gcalloc(gc>info->glyph_cnt?gc:info->glyph_cnt,sizeof(uint16));
3119 		kvs = galloc(kv*sizeof(int16));
3120 		kc->offsets = galloc(kc->first_cnt*kc->second_cnt*sizeof(int16));
3121 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3122 		kc->adjusts = gcalloc(kc->first_cnt*kc->second_cnt,sizeof(DeviceTable));
3123 #endif
3124 		for ( i=0; i<kv; ++i )
3125 		    kvs[i] = (int16) getushort(ttf);
3126 		for ( i=0; i<gc; ++i )
3127 		    class1[i] = getc(ttf);
3128 		for ( i=0; i<gc; ++i )
3129 		    class2[i] = getc(ttf);
3130 		for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i )
3131 		    kc->offsets[i] = kvs[getc(ttf)];
3132 		free(kvs);
3133 	    }
3134 	    kc->firsts = ClassToNames(info,kc->first_cnt,class1,info->glyph_cnt);
3135 	    kc->seconds = ClassToNames(info,kc->second_cnt,class2,info->glyph_cnt);
3136 	    for ( i=0; i<info->glyph_cnt; ++i ) {
3137 		if ( class1[i]>=4 && info->chars[i]!=NULL )
3138 		    FListsAppendScriptLang(otl->features,
3139 			    SCScriptFromUnicode(info->chars[i]),
3140 			    DEFAULT_LANG);
3141 	    }
3142 	    free(class1); free(class2);
3143 	    fseek(ttf,begin_table+len,SEEK_SET);
3144 	    otl->subtables[0].kc = kc;
3145 	    kc->subtable = otl->subtables;
3146 	    InfoNameOTLookup(otl,info);
3147 	} else {
3148 	    LogError(_("Invalid or unsupported format (%d) for subtable of 'kern' table"), format );
3149 	    info->bad_gx = true;
3150 	    fseek(ttf,len-header_size,SEEK_CUR);
3151 	    if ( otl!=NULL )
3152 		OTLRemove(info,otl,true);
3153 	}
3154     }
3155 }
3156 
3157 /******************************************************************************/
3158 /* ******************************* MATH Table ******************************* */
3159 /* ********************** (Not strictly OpenType yet) *********************** */
3160 /******************************************************************************/
3161 
3162 /* ******************************** Read MATH ******************************* */
3163 
ttf_math_read_constants(FILE * ttf,struct ttfinfo * info,uint32 start)3164 static void ttf_math_read_constants(FILE *ttf,struct ttfinfo *info, uint32 start) {
3165     struct MATH *math;
3166     int i;
3167 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3168     uint16 off;
3169 #endif
3170 
3171     fseek(ttf,start,SEEK_SET);
3172     info->math = math = gcalloc(1,sizeof(struct MATH));
3173 
3174     for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
3175 	int16 *pos = (int16 *) (((char *) (math)) + math_constants_descriptor[i].offset );
3176 	if ( pos == (int16 *) &math->MinConnectorOverlap )
3177     continue;		/* Actually lives in the Variant table, not here */
3178 	*pos = getushort(ttf);
3179 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3180 	if ( math_constants_descriptor[i].devtab_offset >= 0 ) {
3181 	    DeviceTable **devtab = (DeviceTable **) (((char *) (math)) + math_constants_descriptor[i].devtab_offset );
3182 	    off = getushort(ttf);
3183 	    if ( off!=0 ) {
3184 		*devtab = chunkalloc(sizeof(DeviceTable));
3185 		ReadDeviceTable(ttf,*devtab,start+off,info);
3186 	    }
3187 	}
3188 #else
3189 	/* No support for device tables, skip it */
3190 	if ( math_constants_descriptor[i].devtab_offset != -1 )
3191 	    (void) getushort(ttf);
3192 #endif
3193     }
3194 }
3195 
ttf_math_read_icta(FILE * ttf,struct ttfinfo * info,uint32 start,int is_ic)3196 static void ttf_math_read_icta(FILE *ttf,struct ttfinfo *info, uint32 start, int is_ic) {
3197     /* The italic correction and top accent sub-tables have the same format */
3198     int coverage, cnt, i, val, offset;
3199     uint16 *glyphs;
3200 
3201     fseek(ttf,start,SEEK_SET);
3202     coverage = getushort(ttf);
3203     cnt = getushort(ttf);
3204     glyphs = getCoverageTable(ttf,start+coverage,info);
3205     if ( glyphs==NULL )
3206 return;
3207     fseek(ttf,start+4,SEEK_SET);
3208     for ( i=0; i<cnt; ++i ) {
3209       val = (int16) getushort(ttf);
3210       offset = getushort(ttf);
3211       if ( glyphs[i]<info->glyph_cnt && info->chars[ glyphs[i]]!=NULL ) {
3212 	if ( is_ic )
3213 	    info->chars[ glyphs[i] ]->italic_correction = val;
3214 	else
3215 	    info->chars[ glyphs[i] ]->top_accent_horiz = val;
3216 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3217 	if ( offset!=0 ) {
3218 	    DeviceTable *dv = chunkalloc(sizeof(DeviceTable));
3219 	    ReadDeviceTable(ttf,dv,start+offset,info);
3220 	    if ( is_ic )
3221 		info->chars[ glyphs[i] ]->italic_adjusts = dv;
3222 	    else
3223 		info->chars[ glyphs[i] ]->top_accent_adjusts = dv;
3224 	}
3225 #endif
3226       }
3227     }
3228     free(glyphs);
3229 }
3230 
ttf_math_read_extended(FILE * ttf,struct ttfinfo * info,uint32 start)3231 static void ttf_math_read_extended(FILE *ttf,struct ttfinfo *info, uint32 start) {
3232     int i;
3233     uint16 *glyphs;
3234 
3235     glyphs = getCoverageTable(ttf,start,info);
3236     if ( glyphs==NULL )
3237 return;
3238     for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt && info->chars[ glyphs[i]]!=NULL )
3239 	info->chars[ glyphs[i] ]->is_extended_shape = true;
3240     free(glyphs);
3241 }
3242 
ttf_math_read_mathkernv(FILE * ttf,uint32 start,struct mathkernvertex * mkv,SplineChar * sc,int istop,struct ttfinfo * info)3243 static void ttf_math_read_mathkernv(FILE *ttf, uint32 start,struct mathkernvertex *mkv,
3244 	SplineChar *sc, int istop, struct ttfinfo *info) {
3245     int cnt, i;
3246     (void)info; /* for -Wall */
3247     fseek(ttf,start,SEEK_SET);
3248     /* There is one more width than height. I store the width count */
3249     /*  and guess a dummy height later */
3250     mkv->cnt = cnt = getushort(ttf)+1;
3251     mkv->mkd = gcalloc(cnt,sizeof(struct mathkerndata));
3252 
3253     for ( i=0; i<cnt-1; ++i ) {
3254 	mkv->mkd[i].height = getushort(ttf);
3255 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3256 	mkv->mkd[i].height_adjusts = (void *) (intpt) getushort(ttf);
3257 #else
3258 	(void) getushort(ttf);
3259 #endif
3260     }
3261 
3262     for ( i=0; i<cnt; ++i ) {
3263 	mkv->mkd[i].kern = getushort(ttf);
3264 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3265 	mkv->mkd[i].kern_adjusts = (void *) (intpt) getushort(ttf);
3266 #else
3267 	(void) getushort(ttf);
3268 #endif
3269     }
3270 
3271 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3272     for ( i=0; i<cnt; ++i ) {
3273 	DeviceTable *dv;
3274 	uint32 offset;
3275 	if ( mkv->mkd[i].height_adjusts!=NULL ) {
3276 	    offset = start + (intpt) mkv->mkd[i].height_adjusts;
3277 	    mkv->mkd[i].height_adjusts = dv = chunkalloc(sizeof(DeviceTable));
3278 	    ReadDeviceTable(ttf,dv,offset,info);
3279 	}
3280 	if ( mkv->mkd[i].kern_adjusts!=NULL ) {
3281 	    offset = start + (intpt) mkv->mkd[i].kern_adjusts;
3282 	    mkv->mkd[i].kern_adjusts = dv = chunkalloc(sizeof(DeviceTable));
3283 	    ReadDeviceTable(ttf,dv,offset,info);
3284 	}
3285     }
3286 #endif
3287 
3288     if ( cnt>=3 )
3289 	mkv->mkd[cnt-1].height = 2*mkv->mkd[cnt-2].height - mkv->mkd[cnt-3].height;
3290     else if ( cnt>=2 )
3291 	mkv->mkd[cnt-1].height = mkv->mkd[cnt-2].height + 100;
3292     else if ( cnt==1 ) {
3293 	if ( istop ) {
3294 	    DBounds b;
3295 	    SplineCharQuickBounds(sc,&b);
3296 	    mkv->mkd[cnt-1].height = b.maxy;
3297 	} else
3298 	    mkv->mkd[cnt-1].height = 0;
3299     }
3300 }
3301 
ttf_math_read_mathkern(FILE * ttf,struct ttfinfo * info,uint32 start)3302 static void ttf_math_read_mathkern(FILE *ttf,struct ttfinfo *info, uint32 start) {
3303     int coverage, cnt, i;
3304     uint16 *glyphs;
3305     struct koff { uint16 tr, tl, br, bl; } *koff;
3306 
3307     fseek(ttf,start,SEEK_SET);
3308     coverage = getushort(ttf);
3309     cnt = getushort(ttf);
3310     koff = galloc(cnt*sizeof(struct koff));
3311     for ( i=0; i<cnt; ++i ) {
3312 	koff[i].tr = getushort(ttf);
3313 	koff[i].tl = getushort(ttf);
3314 	koff[i].br = getushort(ttf);
3315 	koff[i].bl = getushort(ttf);
3316     }
3317     glyphs = getCoverageTable(ttf,start+coverage,info);
3318     if ( glyphs==NULL ) {
3319 	free(koff);
3320 return;
3321     }
3322     for ( i=0; i<cnt; ++i ) if ( glyphs[i]<info->glyph_cnt && info->chars[ glyphs[i]]!=NULL ) {
3323 	SplineChar *sc = info->chars[ glyphs[i]];
3324 	sc->mathkern = chunkalloc(sizeof(struct mathkern));
3325 	if ( koff[i].tr!=0 )
3326 	    ttf_math_read_mathkernv(ttf,start+koff[i].tr,&sc->mathkern->top_right,sc,true,info);
3327 	if ( koff[i].tl!=0 )
3328 	    ttf_math_read_mathkernv(ttf,start+koff[i].tl,&sc->mathkern->top_left,sc,true,info);
3329 	if ( koff[i].br!=0 )
3330 	    ttf_math_read_mathkernv(ttf,start+koff[i].br,&sc->mathkern->bottom_right,sc,false,info);
3331 	if ( koff[i].bl!=0 )
3332 	    ttf_math_read_mathkernv(ttf,start+koff[i].bl,&sc->mathkern->bottom_left,sc,false,info);
3333     }
3334     free(koff);
3335     free(glyphs);
3336 }
3337 
ttf_math_read_glyphinfo(FILE * ttf,struct ttfinfo * info,uint32 start)3338 static void ttf_math_read_glyphinfo(FILE *ttf,struct ttfinfo *info, uint32 start) {
3339     int icoff,taoff,esoff,kioff;
3340 
3341     fseek(ttf,start,SEEK_SET);
3342     icoff = getushort(ttf);
3343     taoff = getushort(ttf);
3344     esoff = getushort(ttf);
3345     kioff = getushort(ttf);
3346 
3347     if ( icoff!=0 )
3348 	ttf_math_read_icta(ttf,info,start+icoff,true);
3349     if ( taoff!=0 )
3350 	ttf_math_read_icta(ttf,info,start+taoff,false);
3351     if ( esoff!=0 )
3352 	ttf_math_read_extended(ttf,info,start+esoff);
3353     if ( kioff!=0 )
3354 	ttf_math_read_mathkern(ttf,info,start+kioff);
3355 }
3356 
ttf_math_read_gvtable(FILE * ttf,struct ttfinfo * info,uint32 start,enum gsub_inusetype justinuse,SplineChar * basesc,int isv)3357 static struct glyphvariants *ttf_math_read_gvtable(FILE *ttf,struct ttfinfo *info, uint32 start,
3358 	enum gsub_inusetype justinuse, SplineChar *basesc, int isv ) {
3359     struct glyphvariants *gv = chunkalloc(sizeof(struct glyphvariants));
3360     int ga_offset;
3361     int vcnt;
3362     uint16 *glyphs;
3363     int i, j, len;
3364     char *pt;
3365     int ic_offset, pcnt;
3366     SplineChar *sc;
3367     char ebuf[20], buffer[50], *ext;
3368 
3369     fseek(ttf,start,SEEK_SET);
3370     ga_offset = getushort(ttf);
3371     vcnt      = getushort(ttf);
3372     if ( vcnt!=0 ) {
3373 	if ( justinuse==git_justinuse ) {
3374 	    for ( i=0; i<vcnt; ++i ) {
3375 		int gid = getushort(ttf);
3376 		/* sizes[i] = */ getushort(ttf);
3377 		if ( gid>=0 && gid<info->glyph_cnt )
3378 		    info->inuse[gid] = true;
3379 	    }
3380 	} else if ( justinuse==git_findnames ) {
3381 	    for ( i=0; i<vcnt; ++i ) {
3382 		int gid = getushort(ttf);
3383 		/* sizes[i] = */ getushort(ttf);
3384 		if ( basesc!=NULL && basesc->name!=NULL &&
3385 			gid>=0 && gid<info->glyph_cnt &&
3386 			(sc = info->chars[gid])!=NULL && sc->name==NULL ) {
3387 		    snprintf(buffer,sizeof(buffer),"%.30s.%csize%d",
3388 			    basesc->name, isv?'v':'h', i);
3389 		    sc->name = copy(buffer);
3390 		}
3391 	    }
3392 	} else {
3393 	    glyphs    = galloc(vcnt*sizeof(uint16));
3394 	    len = 0;
3395 	    for ( i=0; i<vcnt; ++i ) {
3396 		glyphs[i]      = getushort(ttf);
3397 		/* sizes[i] = */ getushort(ttf);
3398 		if ( glyphs[i]<info->glyph_cnt && (sc = info->chars[ glyphs[i]])!=NULL )
3399 		    len += strlen(sc->name)+1;
3400 	    }
3401 	    if ( len!=0 ) {
3402 		gv->variants = pt = galloc(len);
3403 		for ( i=len=0; i<vcnt; ++i ) {
3404 		    if ( glyphs[i]<info->glyph_cnt && (sc = info->chars[ glyphs[i]])!=NULL ) {
3405 			strcpy(pt+len,sc->name);
3406 			len += strlen(sc->name);
3407 			pt[len++] = ' ';
3408 		    }
3409 		}
3410 		pt[len-1] = '\0';
3411 	    }
3412 	    free(glyphs);
3413 	}
3414     }
3415     if ( ga_offset!=0 ) {
3416 	start += ga_offset;
3417 	fseek(ttf,start,SEEK_SET);
3418 	gv->italic_correction = getushort(ttf);
3419 	ic_offset = getushort(ttf);
3420 	gv->part_cnt = pcnt = getushort(ttf);
3421 	if ( justinuse==git_normal )
3422 	    gv->parts = gcalloc(pcnt,sizeof(struct gv_part));
3423 	for ( i=j=0; i<pcnt; ++i ) {
3424 	    int gid, start, end, full, flags;
3425 	    gid = getushort(ttf);
3426 	    start = getushort(ttf);
3427 	    end = getushort(ttf);
3428 	    full = getushort(ttf);
3429 	    flags = getushort(ttf);
3430 	    if ( feof(ttf)) {
3431 		LogError( _("Bad glyph variant subtable of MATH table.\n") );
3432 		info->bad_ot = true;
3433 		chunkfree(gv,sizeof(*gv));
3434 return( NULL );
3435 	    }
3436 	    if ( justinuse==git_justinuse ) {
3437 		if ( gid<info->glyph_cnt )
3438 		    info->inuse[gid] = true;
3439 	    } else if ( justinuse==git_findnames ) {
3440 		if ( basesc!=NULL && basesc->name!=NULL &&
3441 			gid>=0 && gid<info->glyph_cnt &&
3442 			(sc = info->chars[gid])!=NULL && sc->name==NULL ) {
3443 		    if ( pcnt==1 )
3444 			ext = "repeat";
3445 		    if ( i==0 )
3446 			ext = isv ? "bot" : "left";
3447 		    else if ( i==pcnt-1 )
3448 			ext = isv ? "top" : "right";
3449 		    else if ( i==1 && pcnt==3 )
3450 			ext = "mid";
3451 		    else {
3452 			sprintf( ebuf, "%cpart%d", isv?'v':'h', i );
3453 			ext = ebuf;
3454 		    }
3455 		    snprintf(buffer,sizeof(buffer),"%.30s.%s",
3456 			    basesc->name, ext );
3457 		    sc->name = copy(buffer);
3458 		}
3459 	    } else {
3460 		if ( gid<info->glyph_cnt && (sc = info->chars[gid])!=NULL ) {
3461 		    gv->parts[j].component = copy( sc->name );
3462 		    gv->parts[j].startConnectorLength = start;
3463 		    gv->parts[j].endConnectorLength = end;
3464 		    gv->parts[j].fullAdvance = full;
3465 		    gv->parts[j++].is_extender = flags&1;
3466 		}
3467 	    }
3468 	}
3469 	gv->part_cnt = j;
3470 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3471 	if ( ic_offset!=0 && justinuse==git_normal ) {
3472 	    gv->italic_adjusts = chunkalloc(sizeof(DeviceTable));
3473 	    ReadDeviceTable(ttf,gv->italic_adjusts,start+ic_offset,info);
3474 	}
3475 #endif
3476     }
3477     if ( justinuse==git_justinuse ) {
3478 	chunkfree(gv,sizeof(*gv));
3479 return( NULL );
3480     }
3481 return( gv );
3482 }
3483 
ttf_math_read_variants(FILE * ttf,struct ttfinfo * info,uint32 start,enum gsub_inusetype justinuse)3484 static void ttf_math_read_variants(FILE *ttf,struct ttfinfo *info, uint32 start,
3485 	enum gsub_inusetype justinuse) {
3486     int vcoverage, hcoverage, vcnt, hcnt;
3487     int *hoffs, *voffs;
3488     uint16 *hglyphs, *vglyphs;
3489     int i;
3490 
3491     fseek(ttf,start,SEEK_SET);
3492     if ( info->math==NULL )
3493 	info->math = gcalloc(1,sizeof(struct MATH));
3494     info->math->MinConnectorOverlap = getushort(ttf);
3495     vcoverage = getushort(ttf);
3496     hcoverage = getushort(ttf);
3497     vcnt = getushort(ttf);
3498     hcnt = getushort(ttf);
3499     hoffs = galloc(hcnt*sizeof(int));
3500     voffs = galloc(vcnt*sizeof(int));
3501 
3502     for ( i=0; i<vcnt; ++i )
3503 	voffs[i] = getushort(ttf);
3504     for ( i=0; i<hcnt; ++i )
3505 	hoffs[i] = getushort(ttf);
3506     vglyphs = hglyphs = NULL;
3507     if ( vcoverage!=0 )
3508 	vglyphs = getCoverageTable(ttf,start+vcoverage,info);
3509     if ( hcoverage!=0 )
3510 	hglyphs = getCoverageTable(ttf,start+hcoverage,info);
3511 
3512     if ( vglyphs!=NULL ) {
3513 	for ( i=0; i<vcnt; ++i ) if ( vglyphs[i]<info->glyph_cnt && voffs[i]!=0) {
3514 	    if ( justinuse == git_normal || justinuse == git_findnames ) {
3515 		SplineChar *sc = info->chars[ vglyphs[i]];
3516 		if ( sc!=NULL )
3517 		    sc->vert_variants = ttf_math_read_gvtable(ttf,info,start+voffs[i],justinuse,sc,true);
3518 	    } else if ( info->inuse[ vglyphs[i]])
3519 		ttf_math_read_gvtable(ttf,info,start+voffs[i],justinuse,NULL,true);
3520 	}
3521     }
3522     if ( hglyphs!=NULL ) {
3523 	for ( i=0; i<hcnt; ++i ) if ( hglyphs[i]<info->glyph_cnt && hoffs[i]!=0) {
3524 	    if ( justinuse == git_normal || justinuse == git_findnames ) {
3525 		SplineChar *sc = info->chars[ hglyphs[i]];
3526 		if ( sc!=NULL )
3527 		    sc->horiz_variants = ttf_math_read_gvtable(ttf,info,start+hoffs[i],justinuse,sc,false);
3528 	    } else if ( info->inuse[ hglyphs[i]])
3529 		    ttf_math_read_gvtable(ttf,info,start+hoffs[i],justinuse,NULL,false);
3530 	}
3531     }
3532 
3533     free(vglyphs); free(voffs);
3534     free(hglyphs); free(hoffs);
3535 }
3536 
_otf_read_math(FILE * ttf,struct ttfinfo * info,enum gsub_inusetype justinuse)3537 static void _otf_read_math(FILE *ttf,struct ttfinfo *info,
3538 	enum gsub_inusetype justinuse) {
3539     int constants, glyphinfo, variants;
3540     if ( info->math_start==0 )
3541 return;
3542     fseek(ttf,info->math_start,SEEK_SET);
3543 
3544     info->g_bounds = info->math_start+info->math_length;
3545 
3546     if ( getlong(ttf)!=0x00010000 )
3547 return;
3548     constants = getushort(ttf);
3549     glyphinfo = getushort(ttf);
3550     variants = getushort(ttf);
3551 
3552     if ( justinuse == git_normal ) {
3553 	if ( constants!=0 )
3554 	    ttf_math_read_constants(ttf,info,info->math_start+constants);
3555 	if ( glyphinfo!=0 )
3556 	    ttf_math_read_glyphinfo(ttf,info,info->math_start+glyphinfo);
3557     }
3558     if ( variants!=0 )
3559 	ttf_math_read_variants(ttf,info,info->math_start+variants,justinuse);
3560     if ( ftell(ttf)>info->g_bounds ) {
3561 	LogError("MATH table extends beyond table bounds");
3562 	info->bad_ot = true;
3563     }
3564     info->g_bounds = 0;
3565 }
3566 
otf_read_math(FILE * ttf,struct ttfinfo * info)3567 void otf_read_math(FILE *ttf,struct ttfinfo *info) {
3568     _otf_read_math(ttf,info,git_normal);
3569 }
3570 
otf_read_math_used(FILE * ttf,struct ttfinfo * info)3571 void otf_read_math_used(FILE *ttf,struct ttfinfo *info) {
3572     _otf_read_math(ttf,info,git_justinuse);
3573 }
3574 
GuessNamesFromMATH(FILE * ttf,struct ttfinfo * info)3575 void GuessNamesFromMATH(FILE *ttf,struct ttfinfo *info) {
3576     _otf_read_math(ttf,info,git_findnames);
3577 }
3578 
readttfbaseminmax(FILE * ttf,uint32 offset,struct ttfinfo * info,uint32 script_tag,uint32 lang_tag)3579 static struct baselangextent *readttfbaseminmax(FILE *ttf,uint32 offset,struct ttfinfo *info,
3580 	uint32 script_tag,uint32 lang_tag) {
3581     int j,feat_cnt;
3582     struct baselangextent *lang, *cur, *last;
3583     (void)info; /* for -Wall */
3584     (void)script_tag; /* for -Wall */
3585     fseek(ttf,offset,SEEK_SET);
3586     lang = chunkalloc(sizeof(struct baselangextent));
3587     lang->lang = lang_tag;
3588     lang->descent = (short) getushort(ttf);
3589     lang->ascent  = (short) getushort(ttf);
3590 
3591     feat_cnt = getushort(ttf);
3592     last = NULL;
3593     for ( j=0; j<feat_cnt; ++j ) {
3594 	cur = chunkalloc(sizeof(struct baselangextent));
3595 	if ( last==NULL )
3596 	    lang->features = cur;
3597 	else
3598 	    last->next = cur;
3599 	last = cur;
3600 	cur->lang = getlong(ttf);		/* Actually feature tag here */
3601 	cur->descent = (short) getushort(ttf);
3602 	cur->ascent  = (short) getushort(ttf);
3603     }
3604 return( lang );
3605 }
3606 
readttfbase(FILE * ttf,struct ttfinfo * info)3607 void readttfbase(FILE *ttf,struct ttfinfo *info) {
3608     int version;
3609     uint32 axes[2];
3610     uint32 basetags, basescripts;
3611     int basescriptcnt;
3612     struct tagoff { uint32 tag; uint32 offset; } *bs;
3613     int axis,i,j, tot;
3614     struct Base *curBase;
3615     struct basescript *curScript, *last;
3616     struct baselangextent *cur, *lastLang;
3617 
3618     if ( info->base_start==0 )
3619 return;
3620     fseek(ttf,info->base_start,SEEK_SET);
3621 
3622     version = getlong(ttf);
3623     if ( version!=0x00010000 )
3624 return;
3625     axes[0] = getushort(ttf);	/* Horizontal */
3626     axes[1] = getushort(ttf);	/* Vertical */
3627 
3628     for ( axis=0; axis<2; ++axis ) {
3629 	if ( axes[axis]==0 )
3630     continue;
3631 	fseek(ttf,info->base_start+axes[axis],SEEK_SET);
3632 	curBase = chunkalloc(sizeof(struct Base));
3633 	if ( axis==0 ) info->horiz_base = curBase; else info->vert_base = curBase;
3634 	basetags    = getushort(ttf);
3635 	basescripts = getushort(ttf);
3636 	if ( basetags==0 ) {
3637 	    curBase->baseline_cnt = 0;
3638 	    curBase->baseline_tags = NULL;
3639 	} else {
3640 	    fseek(ttf,info->base_start+axes[axis]+basetags,SEEK_SET);
3641 	    curBase->baseline_cnt = getushort(ttf);
3642 	    curBase->baseline_tags = gcalloc(curBase->baseline_cnt,sizeof(uint32));
3643 	    for ( i=0; i<curBase->baseline_cnt; ++i )
3644 		curBase->baseline_tags[i] = getlong(ttf);
3645 	}
3646 	if ( basescripts!=0 ) {
3647 	    fseek(ttf,info->base_start+axes[axis]+basescripts,SEEK_SET);
3648 	    basescriptcnt = getushort(ttf);
3649 	    bs = gcalloc(basescriptcnt,sizeof(struct tagoff));
3650 	    for ( i=0; i<basescriptcnt; ++i ) {
3651 		bs[i].tag    = getlong(ttf);
3652 		bs[i].offset = getushort(ttf);
3653 		if ( bs[i].offset != 0 )
3654 		    bs[i].offset += info->base_start+axes[axis]+basescripts;
3655 	    }
3656 	    last = NULL;
3657 	    for ( i=0; i<basescriptcnt; ++i ) if ( bs[i].offset!=0 ) {
3658 		int basevalues, defminmax;
3659 		int langsyscnt;
3660 		struct tagoff *ls;
3661 		fseek(ttf,bs[i].offset,SEEK_SET);
3662 		basevalues = getushort(ttf);
3663 		defminmax  = getushort(ttf);
3664 		langsyscnt = getushort(ttf);
3665 		ls = gcalloc(langsyscnt,sizeof(struct tagoff));
3666 		for ( j=0; j<langsyscnt; ++j ) {
3667 		    ls[j].tag    = getlong(ttf);
3668 		    ls[j].offset = getushort(ttf);
3669 		}
3670 		curScript = chunkalloc(sizeof(struct basescript));
3671 		if ( last==NULL )
3672 		    curBase->scripts = curScript;
3673 		else
3674 		    last->next = curScript;
3675 		last = curScript;
3676 		curScript->script = bs[i].tag;
3677 		if ( basevalues!=0 ) {
3678 		    int coordcnt;
3679 		    int *coords;
3680 
3681 		    fseek( ttf,bs[i].offset+basevalues,SEEK_SET);
3682 		    curScript->def_baseline = getushort(ttf);
3683 		    tot = coordcnt = getushort(ttf);
3684 		    if ( coordcnt!=curBase->baseline_cnt ) {
3685 			info->bad_ot = true;
3686 			LogError( "!!!!! Coord count (%d) for '%c%c%c%c' script does not match base tag count (%d) in 'BASE' table\n",
3687 				coordcnt,
3688 				bs[i].tag>>24, bs[i].tag>>16, bs[i].tag>>8, bs[i].tag,
3689 				curBase->baseline_cnt );
3690 			if ( tot<curBase->baseline_cnt )
3691 			    tot = curBase->baseline_cnt;
3692 		    }
3693 		    coords = gcalloc(coordcnt,sizeof(int));
3694 		    curScript->baseline_pos = gcalloc(tot,sizeof(int16));
3695 		    for ( j=0; j<coordcnt; ++j )
3696 			coords[j] = getushort(ttf);
3697 		    for ( j=0; j<coordcnt; ++j ) if ( coords[j]!=0 ) {
3698 			int format;
3699 			fseek( ttf,bs[i].offset+basevalues+coords[j],SEEK_SET);
3700 			format = getushort(ttf);
3701 			curScript->baseline_pos[j]  = (short) getushort(ttf);
3702 			if ( format!=1 && format!=2 && format!=3 ) {
3703 			    info->bad_ot = true;
3704 			    LogError("!!!!! Bad Base Coord format (%d) for '%c%c%c%c' in '%c%c%c%c' script in 'BASE' table\n",
3705 					format,
3706 					curBase->baseline_tags[j]>>24, curBase->baseline_tags[j]>>16, curBase->baseline_tags[j]>>8, curBase->baseline_tags[j],
3707 					bs[i].tag>>24, bs[i].tag>>16, bs[i].tag>>8, bs[i].tag );
3708 			}
3709 		    }
3710 		    free(coords);
3711 		}
3712 		lastLang = NULL;
3713 		if ( defminmax!=0 )
3714 		    curScript->langs = lastLang = readttfbaseminmax(ttf,bs[i].offset+defminmax,info,bs[i].tag,DEFAULT_LANG);
3715 		if ( langsyscnt!=0 ) {
3716 		    for ( j=0; j<langsyscnt; ++j ) if ( ls[j].offset!=0 ) {
3717 			cur = readttfbaseminmax(ttf,bs[i].offset+ls[j].offset,info,bs[i].tag,ls[j].tag);
3718 			if ( last==NULL )
3719 			    curScript->langs = cur;
3720 			else
3721 			    lastLang->next = cur;
3722 			lastLang = cur;
3723 		    }
3724 		}
3725 		free(ls);
3726 	    }
3727    	    free(bs);
3728 	}
3729     }
3730 }
3731