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]
15
static void otf_bsearch_params(int num, // {{{
23
assert(entrySelector);
27
for (iA=1,iB=0;iA<=num;iA<<=1,iB++) {}
29
*searchRange=iA*recordSize/2;
31
*rangeShift=num*recordSize-*searchRange;
35
static char *otf_bsearch(char *table, // {{{
36
const char *target,int len,
40
int lower_bound) // return lower_bound, if !=0
42
char *ret=table+rangeShift;
43
if (memcmp(target,ret,len)<0) {
47
for (;entrySelector>0;entrySelector--) {
50
if (memcmp(target,ret,len)<0) {
54
const int result=memcmp(target,ret,len);
57
} else if (lower_bound) {
59
return ret+searchRange;
63
return NULL; // not found;
67
static OTF_FILE *otf_new(FILE *f) // {{{
72
ret=calloc(1,sizeof(OTF_FILE));
75
ret->version=0x00010000;
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) // {{{
90
} else if (length<0) {
95
int res=fseek(otf->f,pos,SEEK_SET);
97
fprintf(stderr,"Seek failed: %s\n", strerror(errno));
101
// (+3)&~3 for checksum...
102
const int pad_len=(length+3)&~3;
104
ours=buf=malloc(sizeof(char)*pad_len);
106
fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
111
res=fread(buf,1,pad_len,otf->f);
113
if (res==length) { // file size not multiple of 4, pad with zero
114
memset(buf+res,0,pad_len-length);
116
fprintf(stderr,"Short read\n");
127
static int otf_get_ttc_start(OTF_FILE *otf,int use_ttc) // {{{
131
if (!otf->numTTC) { // >0 if TTC...
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");
141
return get_ULONG(buf);
145
OTF_FILE *otf_do_load(OTF_FILE *otf,int pos) // {{{
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
169
fprintf(stderr,"Not a ttf font\n");
172
otf->numTables=get_USHORT(buf+4);
175
// {{{ read directory
176
otf->tables=malloc(sizeof(OTF_DIRENT)*otf->numTables);
178
fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
182
for (iA=0;iA<otf->numTables;iA++) {
183
if (!otf_read(otf,buf,pos,16)) {
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");
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");
206
// otf->flags|=OTF_F_DO_CHECKSUM;
207
// {{{ check head table
209
char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&len);
211
(get_ULONG(head+0)!=0x00010000)|| // version
213
(get_ULONG(head+12)!=0x5F0F3CF5)|| // magic
214
(get_SHORT(head+52)!=0x0000) ) { // glyphDataFormat
215
fprintf(stderr,"Unsupported OTF font / head table \n");
221
otf->unitsPerEm=get_USHORT(head+18);
222
otf->indexToLocFormat=get_SHORT(head+50);
224
// {{{ checksum whole file
225
if (otf->flags&OTF_F_DO_CHECKSUM) {
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));
234
csum+=otf_checksum(tmp,len);
236
if (csum!=0xb1b0afba) {
237
fprintf(stderr,"Wrong global checksum\n");
246
// {{{ read maxp table / numGlyphs
247
char *maxp=otf_get_table(otf,OTF_TAG('m','a','x','p'),&len);
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
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
268
fprintf(stderr,"Unsupported OTF font / maxp table \n");
280
OTF_FILE *otf_load(const char *file) // {{{
286
if ((f=fopen(file,"rb"))==NULL) {
288
char *tmp=strrchr(file,'/'),*end;
290
use_ttc=strtoul(tmp+1,&end,10);
292
end=malloc((tmp-file+1)*sizeof(char));
294
fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
297
strncpy(end,file,tmp-file);
304
fprintf(stderr,"Could not open \"%s\": %s\n", file, strerror(errno));
310
fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
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");
327
otf->numTTC=get_ULONG(buf+8);
329
pos=otf_get_ttc_start(otf,use_ttc);
336
fprintf(stderr,"Not a ttf font\n");
342
return otf_do_load(otf,pos);
346
void otf_close(OTF_FILE *otf) // {{{
354
free(otf->glyphOffsets);
362
static int otf_dirent_compare(const void *a,const void *b) // {{{
364
const unsigned int aa=((const OTF_DIRENT *)a)->tag;
365
const unsigned int bb=((const OTF_DIRENT *)b)->tag;
375
int otf_find_table(OTF_FILE *otf,unsigned int tag) // {{{ - table_index or -1 on error
378
// binary search would require raw table
381
if (!otf_read(otf,buf,pos,12)) {
385
const unsigned int numTables=get_USHORT(buf+4);
386
char *tables=malloc(16*numTables);
390
if (!otf_read(otf,tables,pos,16*numTables)) {
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,
399
get_USHORT(buf+10),0);
402
return (result-tables)/16;
405
OTF_DIRENT key={.tag=tag},*res;
406
res=bsearch(&key,otf->tables,otf->numTables,sizeof(otf->tables[0]),otf_dirent_compare);
408
return (res-otf->tables);
412
for (iA=0;iA<otf->numTables;iA++) {
413
if (otf->tables[iA].tag==tag) {
422
char *otf_get_table(OTF_FILE *otf,unsigned int tag,int *ret_len) // {{{
427
const int idx=otf_find_table(otf,tag);
432
const OTF_DIRENT *table=otf->tables+idx;
434
char *ret=otf_read(otf,NULL,table->offset,table->length);
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);
443
if (csum!=table->checkSum) {
444
fprintf(stderr,"Wrong checksum for %c%c%c%c\n",OTF_UNTAG(tag));
449
*ret_len=table->length;
454
int otf_load_glyf(OTF_FILE *otf) // {{{ - 0 on success
456
assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF
458
// {{{ find glyf table
459
iA=otf_find_table(otf,OTF_TAG('g','l','y','f'));
461
fprintf(stderr,"Unsupported OTF font / glyf table \n");
464
otf->glyfTable=otf->tables+iA;
467
// {{{ read loca table
468
char *loca=otf_get_table(otf,OTF_TAG('l','o','c','a'),&len);
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");
475
if (otf->glyphOffsets) {
476
free(otf->glyphOffsets);
479
otf->glyphOffsets=malloc((otf->numGlyphs+1)*sizeof(unsigned int));
480
if (!otf->glyphOffsets) {
481
fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
484
if (otf->indexToLocFormat==0) {
485
for (iA=0;iA<=otf->numGlyphs;iA++) {
486
otf->glyphOffsets[iA]=get_USHORT(loca+iA*2)*2;
488
} else { // indexToLocFormat==1
489
for (iA=0;iA<=otf->numGlyphs;iA++) {
490
otf->glyphOffsets[iA]=get_ULONG(loca+iA*4);
494
if (otf->glyphOffsets[otf->numGlyphs]>otf->glyfTable->length) {
495
fprintf(stderr,"Bad loca table \n");
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];
505
fprintf(stderr,"Bad loca table: glyph len %d\n",glyfLen);
508
if (maxGlyfLen<glyfLen) {
516
otf->gly=malloc(maxGlyfLen*sizeof(char));
518
fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
527
int otf_load_more(OTF_FILE *otf) // {{{ - 0 on success => hhea,hmtx,name,[glyf]
532
if ((otf->flags&OTF_F_FMT_CFF)==0) { // not for CFF
533
if (otf_load_glyf(otf)==-1) {
538
// {{{ read hhea table
539
char *hhea=otf_get_table(otf,OTF_TAG('h','h','e','a'),&len);
541
(get_ULONG(hhea)!=0x00010000)|| // version
543
(get_SHORT(hhea+32)!=0) ) { // metric format
544
fprintf(stderr,"Unsupported OTF font / hhea table \n");
547
otf->numberOfHMetrics=get_USHORT(hhea+34);
551
// {{{ read hmtx table
552
char *hmtx=otf_get_table(otf,OTF_TAG('h','m','t','x'),&len);
554
(len!=otf->numberOfHMetrics*2+otf->numGlyphs*2) ) {
555
fprintf(stderr,"Unsupported OTF font / hmtx table \n");
565
// {{{ read name table
566
char *name=otf_get_table(otf,OTF_TAG('n','a','m','e'),&len);
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");
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");
596
int otf_load_cmap(OTF_FILE *otf) // {{{ - 0 on success
601
char *cmap=otf_get_table(otf,OTF_TAG('c','m','a','p'),&len);
603
(get_USHORT(cmap)!=0x0000)|| // version
604
(len<get_USHORT(cmap+2)*8+4) ) {
605
fprintf(stderr,"Unsupported OTF font / cmap table \n");
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)||
617
(offset+get_USHORT(ndata+2)>len) ) {
618
fprintf(stderr,"Bad cmap table \n");
623
if ( (get_USHORT(nrec)==3)&&
624
(get_USHORT(nrec+2)<=1)&&
625
(get_USHORT(ndata)==4)&&
626
(get_USHORT(ndata+4)==0) ) {
640
int otf_get_width(OTF_FILE *otf,unsigned short gid) // {{{ -1 on error
644
if (gid>=otf->numGlyphs) {
648
// ensure hmtx is there
650
if (otf_load_more(otf)!=0) {
656
return get_width_fast(otf,gid);
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)
662
return get_USHORT(otf->hmtx+gid*4);
663
// TODO? lsb=get_SHORT(otf->hmtx+gid*4+2);
668
static int otf_name_compare(const void *a,const void *b) // {{{
670
return memcmp(a,b,8);
674
const char *otf_get_name(OTF_FILE *otf,int platformID,int encodingID,int languageID,int nameID,int *ret_len) // {{{
679
// ensure name is there
681
if (otf_load_more(otf)!=0) {
689
set_USHORT(key,platformID);
690
set_USHORT(key+2,encodingID);
691
set_USHORT(key+4,languageID);
692
set_USHORT(key+6,nameID);
694
char *res=bsearch(key,otf->name+6,get_USHORT(otf->name+2),12,otf_name_compare);
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);
706
int otf_get_glyph(OTF_FILE *otf,unsigned short gid) // {{{ result in >otf->gly, returns length, -1 on error
709
assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF
711
if (gid>=otf->numGlyphs) {
715
// ensure >glyphOffsets and >gly is there
716
if ( (!otf->gly)||(!otf->glyphOffsets) ) {
717
if (otf_load_more(otf)!=0) {
723
const int len=otf->glyphOffsets[gid+1]-otf->glyphOffsets[gid];
728
assert(otf->glyfTable->length>=otf->glyphOffsets[gid+1]);
729
if (!otf_read(otf,otf->gly,
730
otf->glyfTable->offset+otf->glyphOffsets[gid],len)) {
738
unsigned short otf_from_unicode(OTF_FILE *otf,int unicode) // {{{ 0 = missing
741
assert( (unicode>=0)&&(unicode<65536) );
742
// assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF, other method!
744
// ensure >cmap and >unimap is there
746
if (otf_load_cmap(otf)!=0) {
752
fprintf(stderr,"Unicode (3,1) cmap in format 4 not found\n");
757
// linear search is cache friendly and should be quite fast
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
770
result+=2+segCountX2; // jump over padding into startCode[segCount]
771
const unsigned short startCode=get_USHORT(result);
772
if (startCode>unicode) {
775
result+=2*segCountX2;
776
const unsigned short rangeOffset=get_USHORT(result);
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)
781
const short delta=get_SHORT(result-segCountX2);
782
return (delta+unicode)&0xffff;
789
int otf_action_copy(void *param,int table_no,OUTPUT_FN output,void *context) // {{{
792
const OTF_DIRENT *table=otf->tables+table_no;
794
if (!output) { // get checksum and unpadded length
795
*(unsigned int *)context=table->checkSum;
796
return table->length;
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);
805
int ret=(table->length+3)&~3;
806
(*output)(data,ret,context);
808
return ret; // padded length
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) // {{{
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;
821
if (!output) { // get checksum and unpadded length
822
*(unsigned int *)context=table->checkSum;
823
return table->length;
826
char *data=otf_read(otf,NULL,table->offset,table->length);
830
set_ULONG(data+8,0xb1b0afba-csum); // head. fix global checksum
831
int ret=(table->length+3)&~3;
832
(*output)(data,ret,context);
834
return ret; // padded length
838
int otf_action_replace(void *param,int length,OUTPUT_FN output,void *context) // {{{
841
char pad[4]={0,0,0,0};
843
int ret=(length+3)&~3;
844
if (!output) { // get checksum and unpadded 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;
851
*(unsigned int *)context=otf_checksum(data,length);
856
(*output)(data,length,context);
858
(*output)(pad,ret-length,context);
861
return ret; // padded length
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
868
head, hhea, maxp, OS/2, name, cmap, post, CFF, (other tables, as convenient)
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')}};
894
int otf_write_sfnt(struct _OTF_WRITE *otw,unsigned int version,int numTables,OUTPUT_FN output,void *context) // {{{
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));
908
if (1) { // sort tables
909
int priolist[NUM_PRIO]={0,};
911
// reverse intersection of both sorted arrays
912
int iA=numTables-1,iB=sizeof(otf_tagorder_win)/sizeof(otf_tagorder_win[0])-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
923
for (iA=NUM_PRIO-1;iA>=0;iA--) { // pick the matched tables up in sorted order (bucketsort principle)
925
order[ret--]=priolist[iA]-1;
929
for (iA=0;iA<numTables;iA++) {
935
set_ULONG(start,version);
936
set_USHORT(start+4,numTables);
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);
943
// first pass: calculate table directory / offsets and checksums
944
unsigned int globalSum=0,csum;
945
int offset=12+16*numTables;
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);
951
if (otw[order[iA]].tag==OTF_TAG('h','e','a','d')) {
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
962
// second pass: write actual data
963
// write header + directory
965
(*output)(start,ret,context);
966
globalSum+=otf_checksum(start,ret);
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;
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);
982
assert(((res+3)&~3)==res); // correctly padded? (i.e. next line is just ret+=res;)