~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to fontembed/sfnt.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-07-22 18:57:32 UTC
  • mfrom: (1.1.17)
  • Revision ID: package-import@ubuntu.com-20120722185732-26kkte5p1lth3rt5
Tags: 1.0.20-0bzr1
* New upstream release
   - pdftops: Added another workaround for Kyocera printers: Some
     models get very slow on images which request interpolation,
     so now we remove the image interpolation requests by additional
     PostScript code only inserted for Kyocera printers (LP: #1026974).
   - Made the Poppler-based filters pdftopdf and pdftoopvp build with
     both Poppler 0.18.x and 0.20.x (Upstream bug #1055).
   - Fixes according to Coverity scan results (Upstream bug #1054).
   - Switched build system to autotools. This especially fixes several
     build problems in Gentoo. Also build-tested with CUPS 1.6.0b1.
   - Fixes for compatibility with clang/gcc-4.7.
   - textonly: Filter did not work as a pipe with copies=1 (Upstream bug
     #1032).
   - texttopdf: Avoid trimming the results of FcFontSort(), as this may
     miss some reasonable candidates under certain circumstances. BTW,
     fix passing a non-pointer as a pointer to "result" (Closes: #670055).
   - Corrected documentation. The option for the maximum image rendering
     resolution in pdftops is "pdftops-max-image-resolution", not
     "pdftops-max-image-resolution-default".
* debian/patches/fcfontsort-no-trim.patch: Removed, fixed upstream.
* debian/rules: Updated options for ./configure and make for the new autotools
  build system.
* debian/watch: Switched to bz2 upstream packages.
* debian/rules, debian/copyright, debian/cups-filters.docs: Updated for
  renamed documentation files.
* debian/control, debian/libfontembed1.install,
  debian/libfontembed-dev.install: Added new binary packages for libfontembed.
* debian/copyright: Updated for recent file additions, and rearrangement of
  directories.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "sfnt.h"
 
2
#include <stdio.h>
 
3
#include <stdlib.h>
 
4
#include <string.h>
 
5
#include <errno.h>
 
6
#include <assert.h>
 
7
#include "sfnt_int.h"
 
8
 
 
9
// TODO?
 
10
// get_SHORT(head+48) // fontDirectionHint
 
11
/* reqd. Tables: cmap, head, hhea, hmtx, maxp, name, OS/2, post
 
12
 OTF: glyf,loca [cvt,fpgm,prep]
 
13
 */
 
14
 
 
15
static void otf_bsearch_params(int num, // {{{
 
16
                               int recordSize,
 
17
                               int *searchRange,
 
18
                               int *entrySelector,
 
19
                               int *rangeShift)
 
20
{
 
21
  assert(num>0);
 
22
  assert(searchRange);
 
23
  assert(entrySelector);
 
24
  assert(rangeShift);
 
25
 
 
26
  int iA,iB;
 
27
  for (iA=1,iB=0;iA<=num;iA<<=1,iB++) {}
 
28
 
 
29
  *searchRange=iA*recordSize/2;
 
30
  *entrySelector=iB-1;
 
31
  *rangeShift=num*recordSize-*searchRange;
 
32
}
 
33
// }}}
 
34
 
 
35
static char *otf_bsearch(char *table, // {{{
 
36
                         const char *target,int len,
 
37
                         int searchRange,
 
38
                         int entrySelector,
 
39
                         int rangeShift,
 
40
                         int lower_bound) // return lower_bound, if !=0
 
41
{
 
42
  char *ret=table+rangeShift;
 
43
  if (memcmp(target,ret,len)<0) {
 
44
    ret=table;
 
45
  }
 
46
 
 
47
  for (;entrySelector>0;entrySelector--) {
 
48
    searchRange>>=1;
 
49
    ret+=searchRange;
 
50
    if (memcmp(target,ret,len)<0) {
 
51
      ret-=searchRange;
 
52
    }
 
53
  }
 
54
  const int result=memcmp(target,ret,len);
 
55
  if (result==0) {
 
56
    return ret;
 
57
  } else if (lower_bound) {
 
58
    if (result>0) {
 
59
      return ret+searchRange;
 
60
    }
 
61
    return ret;
 
62
  }
 
63
  return NULL; // not found;
 
64
}
 
65
// }}}
 
66
 
 
67
static OTF_FILE *otf_new(FILE *f) // {{{
 
68
{
 
69
  assert(f);
 
70
 
 
71
  OTF_FILE *ret;
 
72
  ret=calloc(1,sizeof(OTF_FILE));
 
73
  if (ret) {
 
74
    ret->f=f;
 
75
    ret->version=0x00010000;
 
76
  }
 
77
 
 
78
  return ret;
 
79
}
 
80
// }}}
 
81
 
 
82
// will alloc, if >buf ==NULL, returns >buf, or NULL on error
 
83
// NOTE: you probably want otf_get_table()
 
84
static char *otf_read(OTF_FILE *otf,char *buf,long pos,int length) // {{{
 
85
{
 
86
  char *ours=NULL;
 
87
 
 
88
  if (length==0) {
 
89
    return buf;
 
90
  } else if (length<0) {
 
91
    assert(0);
 
92
    return NULL;
 
93
  }
 
94
 
 
95
  int res=fseek(otf->f,pos,SEEK_SET);
 
96
  if (res==-1) {
 
97
    fprintf(stderr,"Seek failed: %s\n", strerror(errno));
 
98
    return NULL;
 
99
  }
 
100
 
 
101
  // (+3)&~3 for checksum...
 
102
  const int pad_len=(length+3)&~3;
 
103
  if (!buf) {
 
104
    ours=buf=malloc(sizeof(char)*pad_len);
 
105
    if (!buf) {
 
106
      fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
107
      return NULL;
 
108
    }
 
109
  }
 
110
 
 
111
  res=fread(buf,1,pad_len,otf->f);
 
112
  if (res!=pad_len) {
 
113
    if (res==length) { // file size not multiple of 4, pad with zero
 
114
      memset(buf+res,0,pad_len-length);
 
115
    } else {
 
116
      fprintf(stderr,"Short read\n");
 
117
      free(ours);
 
118
      return NULL;
 
119
    }
 
120
  }
 
121
 
 
122
  return buf;
 
123
}
 
124
// }}}
 
125
 
 
126
 
 
127
static int otf_get_ttc_start(OTF_FILE *otf,int use_ttc) // {{{
 
128
{
 
129
  char buf[4];
 
130
 
 
131
  if (!otf->numTTC) { // >0 if TTC...
 
132
    return 0;
 
133
  }
 
134
 
 
135
  int pos=0;
 
136
  if ( (use_ttc<0)||(use_ttc>=otf->numTTC)||
 
137
       (!otf_read(otf,buf,pos+12+4*use_ttc,4)) ) {
 
138
    fprintf(stderr,"Bad TTC subfont number\n");
 
139
    return -1;
 
140
  }
 
141
  return get_ULONG(buf);
 
142
}
 
143
// }}}
 
144
 
 
145
OTF_FILE *otf_do_load(OTF_FILE *otf,int pos) // {{{
 
146
{
 
147
  int iA;
 
148
  char buf[16];
 
149
 
 
150
  // {{{ read offset table
 
151
  if (otf_read(otf,buf,pos,12)) {
 
152
    otf->version=get_ULONG(buf);
 
153
    if (otf->version==0x00010000) { // 1.0 truetype
 
154
    } else if (otf->version==OTF_TAG('O','T','T','O')) { // OTF(CFF)
 
155
      otf->flags|=OTF_F_FMT_CFF;
 
156
    } else if (otf->version==OTF_TAG('t','r','u','e')) { // (old mac)
 
157
    } else if (otf->version==OTF_TAG('t','y','p','1')) { // sfnt wrapped type1
 
158
      // TODO: unsupported
 
159
    } else {
 
160
      otf_close(otf);
 
161
      otf=NULL;
 
162
    }
 
163
    pos+=12;
 
164
  } else {
 
165
    otf_close(otf);
 
166
    otf=NULL;
 
167
  }
 
168
  if (!otf) {
 
169
    fprintf(stderr,"Not a ttf font\n");
 
170
    return NULL;
 
171
  }
 
172
  otf->numTables=get_USHORT(buf+4);
 
173
  // }}}
 
174
 
 
175
  // {{{ read directory
 
176
  otf->tables=malloc(sizeof(OTF_DIRENT)*otf->numTables);
 
177
  if (!otf->tables) {
 
178
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
179
    otf_close(otf);
 
180
    return NULL;
 
181
  }
 
182
  for (iA=0;iA<otf->numTables;iA++) {
 
183
    if (!otf_read(otf,buf,pos,16)) {
 
184
      otf_close(otf);
 
185
      return NULL;
 
186
    }
 
187
    otf->tables[iA].tag=get_ULONG(buf);
 
188
    otf->tables[iA].checkSum=get_ULONG(buf+4);
 
189
    otf->tables[iA].offset=get_ULONG(buf+8);
 
190
    otf->tables[iA].length=get_ULONG(buf+12);
 
191
    if ( (otf->tables[iA].tag==OTF_TAG('C','F','F',' '))&&
 
192
         ((otf->flags&OTF_F_FMT_CFF)==0) ) {
 
193
      fprintf(stderr,"Wrong magic\n");
 
194
      otf_close(otf);
 
195
      return NULL;
 
196
    } else if ( (otf->tables[iA].tag==OTF_TAG('g','l','y','p'))&&
 
197
                (otf->flags&OTF_F_FMT_CFF) ) {
 
198
      fprintf(stderr,"Wrong magic\n");
 
199
      otf_close(otf);
 
200
      return NULL;
 
201
    }
 
202
    pos+=16;
 
203
  }
 
204
  // }}}
 
205
  
 
206
//  otf->flags|=OTF_F_DO_CHECKSUM;
 
207
  // {{{ check head table
 
208
  int len=0;
 
209
  char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&len);
 
210
  if ( (!head)||
 
211
       (get_ULONG(head+0)!=0x00010000)||  // version
 
212
       (len!=54)||
 
213
       (get_ULONG(head+12)!=0x5F0F3CF5)|| // magic
 
214
       (get_SHORT(head+52)!=0x0000) ) {   // glyphDataFormat
 
215
    fprintf(stderr,"Unsupported OTF font / head table \n");
 
216
    free(head);
 
217
    otf_close(otf);
 
218
    return NULL;
 
219
  }
 
220
  // }}}
 
221
  otf->unitsPerEm=get_USHORT(head+18);
 
222
  otf->indexToLocFormat=get_SHORT(head+50);
 
223
 
 
224
  // {{{ checksum whole file
 
225
  if (otf->flags&OTF_F_DO_CHECKSUM) {
 
226
    unsigned int csum=0;
 
227
    char tmp[1024];
 
228
    rewind(otf->f);
 
229
    while (!feof(otf->f)) {
 
230
      len=fread(tmp,1,1024,otf->f);
 
231
      if (len&3) { // zero padding reqd.
 
232
        memset(tmp+len,0,4-(len&3));
 
233
      }
 
234
      csum+=otf_checksum(tmp,len);
 
235
    }
 
236
    if (csum!=0xb1b0afba) {
 
237
      fprintf(stderr,"Wrong global checksum\n");
 
238
      free(head);
 
239
      otf_close(otf);
 
240
      return NULL;
 
241
    }
 
242
  }
 
243
  // }}}
 
244
  free(head);
 
245
 
 
246
  // {{{ read maxp table / numGlyphs
 
247
  char *maxp=otf_get_table(otf,OTF_TAG('m','a','x','p'),&len);
 
248
  if (maxp) {
 
249
    const unsigned int maxp_version=get_ULONG(maxp);
 
250
    if ( (maxp_version==0x00005000)&&(len==6) ) { // version 0.5
 
251
      otf->numGlyphs=get_USHORT(maxp+4);
 
252
      if ( (otf->flags&OTF_F_FMT_CFF)==0) { // only CFF
 
253
        free(maxp);
 
254
        maxp=NULL;
 
255
      }
 
256
    } else if ( (maxp_version==0x00010000)&&(len==32) ) { // version 1.0
 
257
      otf->numGlyphs=get_USHORT(maxp+4);
 
258
      if (otf->flags&OTF_F_FMT_CFF) { // only TTF
 
259
        free(maxp);
 
260
        maxp=NULL;
 
261
      }
 
262
    } else {
 
263
      free(maxp);
 
264
      maxp=NULL;
 
265
    }
 
266
  }
 
267
  if (!maxp) {
 
268
    fprintf(stderr,"Unsupported OTF font / maxp table \n");
 
269
    free(maxp);
 
270
    otf_close(otf);
 
271
    return NULL;
 
272
  }
 
273
  free(maxp);
 
274
  // }}}
 
275
 
 
276
  return otf;
 
277
}
 
278
// }}}
 
279
 
 
280
OTF_FILE *otf_load(const char *file) // {{{
 
281
{
 
282
  FILE *f;
 
283
  OTF_FILE *otf;
 
284
 
 
285
  int use_ttc=-1;
 
286
  if ((f=fopen(file,"rb"))==NULL) {
 
287
    // check for TTC
 
288
    char *tmp=strrchr(file,'/'),*end;
 
289
    if (tmp) {
 
290
      use_ttc=strtoul(tmp+1,&end,10);
 
291
      if (!*end) {
 
292
        end=malloc((tmp-file+1)*sizeof(char));
 
293
        if (!end) {
 
294
          fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
295
          return NULL;
 
296
        }
 
297
        strncpy(end,file,tmp-file);
 
298
        end[tmp-file]=0;
 
299
        f=fopen(end,"rb");
 
300
        free(end);
 
301
      }
 
302
    }
 
303
    if (!f) {
 
304
      fprintf(stderr,"Could not open \"%s\": %s\n", file, strerror(errno));
 
305
      return NULL;
 
306
    }
 
307
  }
 
308
  otf=otf_new(f);
 
309
  if (!otf) {
 
310
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
311
    fclose(f);
 
312
    return NULL;
 
313
  }
 
314
 
 
315
  char buf[12];
 
316
  int pos=0;
 
317
  // {{{ check for TTC
 
318
  if (otf_read(otf,buf,pos,12)) {
 
319
    const unsigned int version=get_ULONG(buf);
 
320
    if (version==OTF_TAG('t','t','c','f')) {
 
321
      const unsigned int ttc_version=get_ULONG(buf+4);
 
322
      if ( (ttc_version!=0x00010000)&&(ttc_version!=0x00020000) ) {
 
323
        fprintf(stderr,"Unsupported TTC version\n");
 
324
        otf_close(otf);
 
325
        return NULL;
 
326
      }
 
327
      otf->numTTC=get_ULONG(buf+8);
 
328
      otf->useTTC=use_ttc;
 
329
      pos=otf_get_ttc_start(otf,use_ttc);
 
330
      if (pos==-1) {
 
331
        otf_close(otf);
 
332
        return NULL;
 
333
      }
 
334
    }
 
335
  } else {
 
336
    fprintf(stderr,"Not a ttf font\n");
 
337
    otf_close(otf);
 
338
    return NULL;
 
339
  }
 
340
  // }}}
 
341
 
 
342
  return otf_do_load(otf,pos);
 
343
}
 
344
// }}}
 
345
 
 
346
void otf_close(OTF_FILE *otf) // {{{
 
347
{
 
348
  assert(otf);
 
349
  if (otf) {
 
350
    free(otf->gly);
 
351
    free(otf->cmap);
 
352
    free(otf->name);
 
353
    free(otf->hmtx);
 
354
    free(otf->glyphOffsets);
 
355
    fclose(otf->f);
 
356
    free(otf->tables);
 
357
    free(otf);
 
358
  }
 
359
}
 
360
// }}}
 
361
 
 
362
static int otf_dirent_compare(const void *a,const void *b) // {{{
 
363
{
 
364
  const unsigned int aa=((const OTF_DIRENT *)a)->tag;
 
365
  const unsigned int bb=((const OTF_DIRENT *)b)->tag;
 
366
  if (aa<bb) {
 
367
    return -1;
 
368
  } else if (aa>bb) {
 
369
    return 1;
 
370
  }
 
371
  return 0;
 
372
}
 
373
// }}}
 
374
 
 
375
int otf_find_table(OTF_FILE *otf,unsigned int tag) // {{{  - table_index  or -1 on error
 
376
{
 
377
#if 0
 
378
  // binary search would require raw table
 
379
  int pos=0;
 
380
  char buf[12];
 
381
  if (!otf_read(otf,buf,pos,12)) {
 
382
    return -1;
 
383
  }
 
384
  pos=12;
 
385
  const unsigned int numTables=get_USHORT(buf+4);
 
386
  char *tables=malloc(16*numTables);
 
387
  if (!tables) {
 
388
    return -1;
 
389
  }
 
390
  if (!otf_read(otf,tables,pos,16*numTables)) {
 
391
    free(tables);
 
392
    return -1;
 
393
  }
 
394
  char target[]={(tag>>24),(tag>>16),(tag>>8),tag};
 
395
  //  assert(get_USHORT(buf+6)+get_USHORT(buf+10)==16*numTables);
 
396
  char *result=otf_bsearch(tables,target,4,
 
397
                           get_USHORT(buf+6),
 
398
                           get_USHORT(buf+8),
 
399
                           get_USHORT(buf+10),0);
 
400
  free(tables);
 
401
  if (result) {
 
402
    return (result-tables)/16;
 
403
  }
 
404
#elif 1
 
405
  OTF_DIRENT key={.tag=tag},*res;
 
406
  res=bsearch(&key,otf->tables,otf->numTables,sizeof(otf->tables[0]),otf_dirent_compare);
 
407
  if (res) {
 
408
    return (res-otf->tables);
 
409
  }
 
410
#else
 
411
  int iA;
 
412
  for (iA=0;iA<otf->numTables;iA++) {
 
413
    if (otf->tables[iA].tag==tag) {
 
414
      return iA;
 
415
    }
 
416
  }
 
417
#endif
 
418
  return -1;
 
419
}
 
420
// }}}
 
421
 
 
422
char *otf_get_table(OTF_FILE *otf,unsigned int tag,int *ret_len) // {{{
 
423
{
 
424
  assert(otf);
 
425
  assert(ret_len);
 
426
 
 
427
  const int idx=otf_find_table(otf,tag);
 
428
  if (idx==-1) {
 
429
    *ret_len=-1;
 
430
    return NULL;
 
431
  }
 
432
  const OTF_DIRENT *table=otf->tables+idx;
 
433
 
 
434
  char *ret=otf_read(otf,NULL,table->offset,table->length);
 
435
  if (!ret) {
 
436
    return NULL;
 
437
  }
 
438
  if (otf->flags&OTF_F_DO_CHECKSUM) {
 
439
    unsigned int csum=otf_checksum(ret,table->length);
 
440
    if (tag==OTF_TAG('h','e','a','d')) { // special case
 
441
      csum-=get_ULONG(ret+8);
 
442
    }
 
443
    if (csum!=table->checkSum) {
 
444
      fprintf(stderr,"Wrong checksum for %c%c%c%c\n",OTF_UNTAG(tag));
 
445
      free(ret);
 
446
      return NULL;
 
447
    }
 
448
  }
 
449
  *ret_len=table->length;
 
450
  return ret;
 
451
}
 
452
// }}}
 
453
 
 
454
int otf_load_glyf(OTF_FILE *otf) // {{{  - 0 on success
 
455
{
 
456
  assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF
 
457
  int iA,len;
 
458
  // {{{ find glyf table
 
459
  iA=otf_find_table(otf,OTF_TAG('g','l','y','f'));
 
460
  if (iA==-1) {
 
461
    fprintf(stderr,"Unsupported OTF font / glyf table \n");
 
462
    return -1;
 
463
  }
 
464
  otf->glyfTable=otf->tables+iA;
 
465
  // }}}
 
466
 
 
467
  // {{{ read loca table
 
468
  char *loca=otf_get_table(otf,OTF_TAG('l','o','c','a'),&len);
 
469
  if ( (!loca)||
 
470
       (otf->indexToLocFormat>=2)||
 
471
       (((len+3)&~3)!=((((otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2)+3)&~3)) ) {
 
472
    fprintf(stderr,"Unsupported OTF font / loca table \n");
 
473
    return -1;
 
474
  }
 
475
  if (otf->glyphOffsets) {
 
476
    free(otf->glyphOffsets);
 
477
    assert(0);
 
478
  }
 
479
  otf->glyphOffsets=malloc((otf->numGlyphs+1)*sizeof(unsigned int));
 
480
  if (!otf->glyphOffsets) {
 
481
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
482
    return -1;
 
483
  }
 
484
  if (otf->indexToLocFormat==0) {
 
485
    for (iA=0;iA<=otf->numGlyphs;iA++) {
 
486
      otf->glyphOffsets[iA]=get_USHORT(loca+iA*2)*2;
 
487
    }
 
488
  } else { // indexToLocFormat==1
 
489
    for (iA=0;iA<=otf->numGlyphs;iA++) {
 
490
      otf->glyphOffsets[iA]=get_ULONG(loca+iA*4);
 
491
    }
 
492
  }
 
493
  free(loca);
 
494
  if (otf->glyphOffsets[otf->numGlyphs]>otf->glyfTable->length) {
 
495
    fprintf(stderr,"Bad loca table \n");
 
496
    return -1;
 
497
  }
 
498
  // }}}
 
499
  
 
500
  // {{{ allocate otf->gly slot
 
501
  int maxGlyfLen=0;  // no single glyf takes more space
 
502
  for (iA=1;iA<=otf->numGlyphs;iA++) {
 
503
    const int glyfLen=otf->glyphOffsets[iA]-otf->glyphOffsets[iA-1];
 
504
    if (glyfLen<0) {
 
505
      fprintf(stderr,"Bad loca table: glyph len %d\n",glyfLen);
 
506
      return -1;
 
507
    }
 
508
    if (maxGlyfLen<glyfLen) {
 
509
      maxGlyfLen=glyfLen;
 
510
    }
 
511
  }
 
512
  if (otf->gly) {
 
513
    free(otf->gly);
 
514
    assert(0);
 
515
  }
 
516
  otf->gly=malloc(maxGlyfLen*sizeof(char));
 
517
  if (!otf->gly) {
 
518
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
519
    return -1;
 
520
  }
 
521
  // }}}
 
522
 
 
523
  return 0;
 
524
}
 
525
// }}}
 
526
 
 
527
int otf_load_more(OTF_FILE *otf) // {{{  - 0 on success   => hhea,hmtx,name,[glyf]
 
528
{
 
529
  int iA;
 
530
 
 
531
  int len;
 
532
  if ((otf->flags&OTF_F_FMT_CFF)==0) { // not for CFF
 
533
    if (otf_load_glyf(otf)==-1) {
 
534
      return -1;
 
535
    }
 
536
  }
 
537
 
 
538
  // {{{ read hhea table
 
539
  char *hhea=otf_get_table(otf,OTF_TAG('h','h','e','a'),&len);
 
540
  if ( (!hhea)||
 
541
       (get_ULONG(hhea)!=0x00010000)|| // version
 
542
       (len!=36)||
 
543
       (get_SHORT(hhea+32)!=0) ) { // metric format
 
544
    fprintf(stderr,"Unsupported OTF font / hhea table \n");
 
545
    return -1;
 
546
  }
 
547
  otf->numberOfHMetrics=get_USHORT(hhea+34);
 
548
  free(hhea);
 
549
  // }}}
 
550
 
 
551
  // {{{ read hmtx table
 
552
  char *hmtx=otf_get_table(otf,OTF_TAG('h','m','t','x'),&len);
 
553
  if ( (!hmtx)||
 
554
       (len!=otf->numberOfHMetrics*2+otf->numGlyphs*2) ) {
 
555
    fprintf(stderr,"Unsupported OTF font / hmtx table \n");
 
556
    return -1;
 
557
  }
 
558
  if (otf->hmtx) {
 
559
    free(otf->hmtx);
 
560
    assert(0);
 
561
  }
 
562
  otf->hmtx=hmtx;
 
563
  // }}}
 
564
 
 
565
  // {{{ read name table
 
566
  char *name=otf_get_table(otf,OTF_TAG('n','a','m','e'),&len);
 
567
  if ( (!name)||
 
568
       (get_USHORT(name)!=0x0000)|| // version
 
569
       (len<get_USHORT(name+2)*12+6)||
 
570
       (len<=get_USHORT(name+4)) ) {
 
571
    fprintf(stderr,"Unsupported OTF font / name table \n");
 
572
    return -1;
 
573
  }
 
574
  // check bounds
 
575
  int name_count=get_USHORT(name+2);
 
576
  const char *nstore=name+get_USHORT(name+4);
 
577
  for (iA=0;iA<name_count;iA++) {
 
578
    const char *nrec=name+6+12*iA;
 
579
    if (nstore-name+get_USHORT(nrec+10)+get_USHORT(nrec+8)>len) {
 
580
      fprintf(stderr,"Bad name table \n");
 
581
      free(name);
 
582
      return -1;
 
583
    }
 
584
  }
 
585
  if (otf->name) {
 
586
    free(otf->name);
 
587
    assert(0);
 
588
  }
 
589
  otf->name=name;
 
590
  // }}}
 
591
 
 
592
  return 0;
 
593
}
 
594
// }}}
 
595
 
 
596
int otf_load_cmap(OTF_FILE *otf) // {{{  - 0 on success
 
597
{
 
598
  int iA;
 
599
  int len;
 
600
 
 
601
  char *cmap=otf_get_table(otf,OTF_TAG('c','m','a','p'),&len);
 
602
  if ( (!cmap)||
 
603
       (get_USHORT(cmap)!=0x0000)|| // version
 
604
       (len<get_USHORT(cmap+2)*8+4) ) {
 
605
    fprintf(stderr,"Unsupported OTF font / cmap table \n");
 
606
    assert(0);
 
607
    return -1;
 
608
  }
 
609
  // check bounds, find (3,0) or (3,1) [TODO?]
 
610
  const int numTables=get_USHORT(cmap+2);
 
611
  for (iA=0;iA<numTables;iA++) {
 
612
    const char *nrec=cmap+4+8*iA;
 
613
    const unsigned int offset=get_ULONG(nrec+4);
 
614
    const char *ndata=cmap+offset;
 
615
    if ( (ndata<cmap+4+8*numTables)||
 
616
         (offset>=len)||
 
617
         (offset+get_USHORT(ndata+2)>len) ) {
 
618
      fprintf(stderr,"Bad cmap table \n");
 
619
      free(cmap);
 
620
      assert(0);
 
621
      return -1;
 
622
    }
 
623
    if ( (get_USHORT(nrec)==3)&&
 
624
         (get_USHORT(nrec+2)<=1)&&
 
625
         (get_USHORT(ndata)==4)&&
 
626
         (get_USHORT(ndata+4)==0) ) {
 
627
      otf->unimap=ndata;
 
628
    }
 
629
  }
 
630
  if (otf->cmap) {
 
631
    free(otf->cmap);
 
632
    assert(0);
 
633
  }
 
634
  otf->cmap=cmap;
 
635
 
 
636
  return 0;
 
637
}
 
638
// }}}
 
639
 
 
640
int otf_get_width(OTF_FILE *otf,unsigned short gid) // {{{  -1 on error
 
641
{
 
642
  assert(otf);
 
643
 
 
644
  if (gid>=otf->numGlyphs) {
 
645
    return -1;
 
646
  }
 
647
 
 
648
  // ensure hmtx is there
 
649
  if (!otf->hmtx) {
 
650
    if (otf_load_more(otf)!=0) {
 
651
      assert(0);
 
652
      return -1;
 
653
    }
 
654
  }
 
655
 
 
656
  return get_width_fast(otf,gid);
 
657
#if 0
 
658
  if (gid>=otf->numberOfHMetrics) {
 
659
    return get_USHORT(otf->hmtx+(otf->numberOfHMetrics-1)*2);
 
660
    // TODO? lsb=get_SHORT(otf->hmtx+otf->numberOfHMetrics*2+gid*2);  // lsb: left_side_bearing (also in table)
 
661
  }
 
662
  return get_USHORT(otf->hmtx+gid*4);
 
663
  // TODO? lsb=get_SHORT(otf->hmtx+gid*4+2);
 
664
#endif
 
665
}
 
666
// }}}
 
667
 
 
668
static int otf_name_compare(const void *a,const void *b) // {{{
 
669
{
 
670
  return memcmp(a,b,8);
 
671
}
 
672
// }}}
 
673
 
 
674
const char *otf_get_name(OTF_FILE *otf,int platformID,int encodingID,int languageID,int nameID,int *ret_len) // {{{
 
675
{
 
676
  assert(otf);
 
677
  assert(ret_len);
 
678
 
 
679
  // ensure name is there
 
680
  if (!otf->name) {
 
681
    if (otf_load_more(otf)!=0) {
 
682
      *ret_len=-1;
 
683
      assert(0);
 
684
      return NULL;
 
685
    }
 
686
  }
 
687
 
 
688
  char key[8];
 
689
  set_USHORT(key,platformID);
 
690
  set_USHORT(key+2,encodingID);
 
691
  set_USHORT(key+4,languageID);
 
692
  set_USHORT(key+6,nameID);
 
693
 
 
694
  char *res=bsearch(key,otf->name+6,get_USHORT(otf->name+2),12,otf_name_compare);
 
695
  if (res) {
 
696
    *ret_len=get_USHORT(res+8);
 
697
    int npos=get_USHORT(res+10);
 
698
    const char *nstore=otf->name+get_USHORT(otf->name+4);
 
699
    return nstore+npos;
 
700
  }
 
701
  *ret_len=0;
 
702
  return NULL;
 
703
}
 
704
// }}}
 
705
 
 
706
int otf_get_glyph(OTF_FILE *otf,unsigned short gid) // {{{ result in >otf->gly, returns length, -1 on error
 
707
{
 
708
  assert(otf);
 
709
  assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF
 
710
 
 
711
  if (gid>=otf->numGlyphs) {
 
712
    return -1;
 
713
  }
 
714
 
 
715
  // ensure >glyphOffsets and >gly is there
 
716
  if ( (!otf->gly)||(!otf->glyphOffsets) ) {
 
717
    if (otf_load_more(otf)!=0) {
 
718
      assert(0);
 
719
      return -1;
 
720
    }
 
721
  }
 
722
 
 
723
  const int len=otf->glyphOffsets[gid+1]-otf->glyphOffsets[gid];
 
724
  if (len==0) {
 
725
    return 0;
 
726
  }
 
727
 
 
728
  assert(otf->glyfTable->length>=otf->glyphOffsets[gid+1]);
 
729
  if (!otf_read(otf,otf->gly,
 
730
                otf->glyfTable->offset+otf->glyphOffsets[gid],len)) {
 
731
    return -1;
 
732
  }
 
733
 
 
734
  return len;
 
735
}
 
736
// }}}
 
737
 
 
738
unsigned short otf_from_unicode(OTF_FILE *otf,int unicode) // {{{ 0 = missing
 
739
{
 
740
  assert(otf);
 
741
  assert( (unicode>=0)&&(unicode<65536) );
 
742
//  assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF, other method!
 
743
 
 
744
  // ensure >cmap and >unimap is there
 
745
  if (!otf->cmap) {
 
746
    if (otf_load_cmap(otf)!=0) {
 
747
      assert(0);
 
748
      return 0; // TODO?
 
749
    }
 
750
  }
 
751
  if (!otf->unimap) {
 
752
    fprintf(stderr,"Unicode (3,1) cmap in format 4 not found\n");
 
753
    return 0;
 
754
  }
 
755
 
 
756
#if 0
 
757
  // linear search is cache friendly and should be quite fast
 
758
#else
 
759
  const unsigned short segCountX2=get_USHORT(otf->unimap+6);
 
760
  char target[]={unicode>>8,unicode}; // set_USHORT(target,unicode);
 
761
  char *result=otf_bsearch((char *)otf->unimap+14,target,2,
 
762
                           get_USHORT(otf->unimap+8),
 
763
                           get_USHORT(otf->unimap+10),
 
764
                           get_USHORT(otf->unimap+12),1);
 
765
  if (result>=otf->unimap+14+segCountX2) { // outside of endCode[segCount]
 
766
    assert(0); // bad font, no 0xffff sentinel
 
767
    return 0;
 
768
  }
 
769
 
 
770
  result+=2+segCountX2; // jump over padding into startCode[segCount]
 
771
  const unsigned short startCode=get_USHORT(result);
 
772
  if (startCode>unicode) {
 
773
    return 0;
 
774
  }
 
775
  result+=2*segCountX2;
 
776
  const unsigned short rangeOffset=get_USHORT(result);
 
777
  if (rangeOffset) {
 
778
    return get_USHORT(result+rangeOffset+2*(unicode-startCode)); // the so called "obscure indexing trick" into glyphIdArray[]
 
779
    // NOTE: this is according to apple spec; microsoft says we must add delta (probably incorrect; fonts probably have delta==0)
 
780
  } else {
 
781
    const short delta=get_SHORT(result-segCountX2);
 
782
    return (delta+unicode)&0xffff;
 
783
  }
 
784
#endif
 
785
}
 
786
// }}}
 
787
 
 
788
/** output stuff **/
 
789
int otf_action_copy(void *param,int table_no,OUTPUT_FN output,void *context) // {{{
 
790
{
 
791
  OTF_FILE *otf=param;
 
792
  const OTF_DIRENT *table=otf->tables+table_no;
 
793
 
 
794
  if (!output) { // get checksum and unpadded length
 
795
    *(unsigned int *)context=table->checkSum;
 
796
    return table->length;
 
797
  }
 
798
 
 
799
// TODO? copy_block(otf->f,table->offset,(table->length+3)&~3,output,context);
 
800
// problem: PS currently depends on single-output.  also checksum not possible
 
801
  char *data=otf_read(otf,NULL,table->offset,table->length);
 
802
  if (!data) {
 
803
    return -1;
 
804
  }
 
805
  int ret=(table->length+3)&~3;
 
806
  (*output)(data,ret,context);
 
807
  free(data);
 
808
  return ret; // padded length
 
809
}
 
810
// }}}
 
811
 
 
812
// TODO? >modified time-stamp?
 
813
// Note: don't use this directly. otf_write_sfnt will internally replace otf_action_copy for head with this
 
814
int otf_action_copy_head(void *param,int csum,OUTPUT_FN output,void *context) // {{{
 
815
{
 
816
  OTF_FILE *otf=param;
 
817
  const int table_no=otf_find_table(otf,OTF_TAG('h','e','a','d')); // we can't have csum AND table_no ... never mind!
 
818
  assert(table_no!=-1);
 
819
  const OTF_DIRENT *table=otf->tables+table_no;
 
820
 
 
821
  if (!output) { // get checksum and unpadded length
 
822
    *(unsigned int *)context=table->checkSum;
 
823
    return table->length;
 
824
  }
 
825
 
 
826
  char *data=otf_read(otf,NULL,table->offset,table->length);
 
827
  if (!data) {
 
828
    return -1;
 
829
  }
 
830
  set_ULONG(data+8,0xb1b0afba-csum); // head. fix global checksum
 
831
  int ret=(table->length+3)&~3;
 
832
  (*output)(data,ret,context);
 
833
  free(data);
 
834
  return ret; // padded length
 
835
}
 
836
// }}}
 
837
 
 
838
int otf_action_replace(void *param,int length,OUTPUT_FN output,void *context) // {{{
 
839
{
 
840
  char *data=param;
 
841
  char pad[4]={0,0,0,0};
 
842
 
 
843
  int ret=(length+3)&~3;
 
844
  if (!output) { // get checksum and unpadded length
 
845
    if (ret!=length) {
 
846
      unsigned int csum=otf_checksum(data,ret-4);
 
847
      memcpy(pad,data+ret-4,ret-length);
 
848
      csum+=get_ULONG(pad);
 
849
      *(unsigned int *)context=csum;
 
850
    } else {
 
851
      *(unsigned int *)context=otf_checksum(data,length);
 
852
    }
 
853
    return length;
 
854
  }
 
855
 
 
856
  (*output)(data,length,context);
 
857
  if (ret!=length) {
 
858
    (*output)(pad,ret-length,context);
 
859
  }
 
860
 
 
861
  return ret; // padded length
 
862
}
 
863
// }}}
 
864
 
 
865
/* windows "works best" with the following ordering:
 
866
  head, hhea, maxp, OS/2, hmtx, LTSH, VDMX, hdmx, cmap, fpgm, prep, cvt, loca, glyf, kern, name, post, gasp, PCLT, DSIG
 
867
or for CFF:
 
868
  head, hhea, maxp, OS/2, name, cmap, post, CFF, (other tables, as convenient)
 
869
*/
 
870
#define NUM_PRIO 20
 
871
static const struct { int prio; unsigned int tag; } otf_tagorder_win[]={ // {{{
 
872
  {19,OTF_TAG('D','S','I','G')},
 
873
  { 5,OTF_TAG('L','T','S','H')},
 
874
  { 3,OTF_TAG('O','S','/','2')},
 
875
  {18,OTF_TAG('P','C','L','T')},
 
876
  { 6,OTF_TAG('V','D','M','X')},
 
877
  { 8,OTF_TAG('c','m','a','p')},
 
878
  {11,OTF_TAG('c','v','t',' ')},
 
879
  { 9,OTF_TAG('f','p','g','m')},
 
880
  {17,OTF_TAG('g','a','s','p')},
 
881
  {13,OTF_TAG('g','l','y','f')},
 
882
  { 7,OTF_TAG('h','d','m','x')},
 
883
  { 0,OTF_TAG('h','e','a','d')},
 
884
  { 1,OTF_TAG('h','h','e','a')},
 
885
  { 4,OTF_TAG('h','m','t','x')},
 
886
  {14,OTF_TAG('k','e','r','n')},
 
887
  {12,OTF_TAG('l','o','c','a')},
 
888
  { 2,OTF_TAG('m','a','x','p')},
 
889
  {15,OTF_TAG('n','a','m','e')},
 
890
  {16,OTF_TAG('p','o','s','t')},
 
891
  {10,OTF_TAG('p','r','e','p')}};
 
892
// }}}
 
893
 
 
894
int otf_write_sfnt(struct _OTF_WRITE *otw,unsigned int version,int numTables,OUTPUT_FN output,void *context) // {{{
 
895
{
 
896
  int iA;
 
897
  int ret;
 
898
 
 
899
  int *order=malloc(sizeof(int)*numTables); // temporary
 
900
  char *start=malloc(12+16*numTables);
 
901
  if ( (!order)||(!start) ) {
 
902
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
903
    free(order);
 
904
    free(start);
 
905
    return -1;
 
906
  }
 
907
 
 
908
  if (1) { // sort tables 
 
909
    int priolist[NUM_PRIO]={0,};
 
910
 
 
911
    // reverse intersection of both sorted arrays
 
912
    int iA=numTables-1,iB=sizeof(otf_tagorder_win)/sizeof(otf_tagorder_win[0])-1;
 
913
    int ret=numTables-1;
 
914
    while ( (iA>=0)&&(iB>=0) ) {
 
915
      if (otw[iA].tag==otf_tagorder_win[iB].tag) {
 
916
        priolist[otf_tagorder_win[iB--].prio]=1+iA--;
 
917
      } else if (otw[iA].tag>otf_tagorder_win[iB].tag) { // no order known: put unchanged at end of result
 
918
        order[ret--]=iA--;
 
919
      } else { // <
 
920
        iB--;
 
921
      }
 
922
    }
 
923
    for (iA=NUM_PRIO-1;iA>=0;iA--) { // pick the matched tables up in sorted order (bucketsort principle)
 
924
      if (priolist[iA]) {
 
925
        order[ret--]=priolist[iA]-1;
 
926
      }
 
927
    }
 
928
  } else {
 
929
    for (iA=0;iA<numTables;iA++) {
 
930
      order[iA]=iA;
 
931
    }
 
932
  }
 
933
 
 
934
  // the header
 
935
  set_ULONG(start,version);
 
936
  set_USHORT(start+4,numTables);
 
937
  int a,b,c;
 
938
  otf_bsearch_params(numTables,16,&a,&b,&c); 
 
939
  set_USHORT(start+6,a);
 
940
  set_USHORT(start+8,b);
 
941
  set_USHORT(start+10,c);
 
942
 
 
943
  // first pass: calculate table directory / offsets and checksums
 
944
  unsigned int globalSum=0,csum;
 
945
  int offset=12+16*numTables;
 
946
  int headAt=-1;
 
947
  for (iA=0;iA<numTables;iA++) {
 
948
    char *entry=start+12+16*order[iA];
 
949
    const int res=(*otw[order[iA]].action)(otw[order[iA]].param,otw[order[iA]].length,NULL,&csum);
 
950
    assert(res>=0);
 
951
    if (otw[order[iA]].tag==OTF_TAG('h','e','a','d')) {
 
952
      headAt=order[iA];
 
953
    }
 
954
    set_ULONG(entry,otw[order[iA]].tag);
 
955
    set_ULONG(entry+4,csum);
 
956
    set_ULONG(entry+8,offset);
 
957
    set_ULONG(entry+12,res);
 
958
    offset+=(res+3)&~3; // padding
 
959
    globalSum+=csum;
 
960
  }
 
961
 
 
962
  // second pass: write actual data
 
963
  // write header + directory
 
964
  ret=12+16*numTables;
 
965
  (*output)(start,ret,context);
 
966
  globalSum+=otf_checksum(start,ret);
 
967
 
 
968
  // change head
 
969
  if ( (headAt!=-1)&&(otw[headAt].action==otf_action_copy) ) { // more needed?
 
970
    otw[headAt].action=otf_action_copy_head;
 
971
    otw[headAt].length=globalSum;
 
972
  }
 
973
 
 
974
  // write tables
 
975
  for (iA=0;iA<numTables;iA++) {
 
976
    const int res=(*otw[order[iA]].action)(otw[order[iA]].param,otw[order[iA]].length,output,context);
 
977
    if (res<0) {
 
978
      free(order);
 
979
      free(start);
 
980
      return -1;
 
981
    }
 
982
    assert(((res+3)&~3)==res); // correctly padded? (i.e. next line is just ret+=res;)
 
983
    ret+=(res+3)&~3;
 
984
  }
 
985
  assert(offset==ret);
 
986
  free(order);
 
987
  free(start);
 
988
 
 
989
  return ret;
 
990
}
 
991
// }}}
 
992