even more ttf bugfixes
[swftools.git] / lib / ttf.c
1 /* ttf.c
2    Parser and writer for truetype font files.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2010 Matthias Kramm <kramm@quiss.org> 
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <memory.h>
25 #include "log.h"
26 #include "os.h"
27 #include "q.h"
28 #include "mem.h"
29 #include "ttf.h"
30
31 #define TTCFTAG 0x74746366
32
33 #define OPENTYPE 0x4f54544f
34 #define TRUETYPE_MACOS 0x74727565
35 #define VERSION_1_0 0x00010000
36
37 #define TAG_OS2 0x4f532f32
38 #define TAG_CMAP 0x636d6170
39 #define TAG_GLYF 0x676c7966 //required for non opentype
40 #define TAG_HEAD 0x68656164 //required
41 #define TAG_HHEA 0x68686561 //required
42 #define TAG_HMTX 0x686d7478 //required
43 #define TAG_VHEA 0x86686561
44 #define TAG_VMTX 0x866d7478
45 #define TAG_KERN 0x6b65726e
46 #define TAG_LOCA 0x6c6f6361 //required for non opentype
47 #define TAG_MAXP 0x6d617870 //required
48 #define TAG_NAME 0x6e616d65
49 #define TAG_POST 0x706f7374
50 #define TAG_CFF  0x43464620 //required for opentype
51
52 /* TODO:
53     fpgm - assembly instructions
54     prep - assembly instructions
55     cvt - constant value table
56     gasp - gridfitting procedure
57 */
58
59 static U32 checksum_block(U8*_data, int len)
60 {
61     U32 sum = 0;
62     U8*data = (U8*)_data;
63
64     int pos;
65     int len_minus_4 = len-4;
66     for(pos=0;pos<=len_minus_4;pos+=4) {
67         sum += data[pos]<<24|data[pos+1]<<16|data[pos+2]<<8|data[pos+3];
68     }
69     int left = len-pos;
70     if(left == 1) sum+= data[pos+0]<<24;
71     if(left == 2) sum+= data[pos+0]<<24|data[pos+1]<<16;
72     if(left == 3) sum+= data[pos+0]<<24|data[pos+1]<<16|data[pos+2]<<8;
73     return sum;
74 }
75
76 typedef struct _memreader {
77     U8*mem;
78     int pos;
79     int size;
80 } memreader_t;
81
82 static U8 readU8(memreader_t*r)
83 {
84     return r->mem[r->pos++];
85 }
86 static inline U16 readU16(memreader_t*r)
87 {
88     if(r->pos+2>r->size) return 0;
89     U16 val = r->mem[r->pos]<<8|
90               r->mem[r->pos+1];
91     r->pos += 2;
92     return val;
93 }
94 static S16 readS16(memreader_t*r)
95 {
96     return (S16)readU16(r);
97 }
98 static U32 readU32(memreader_t*r)
99 {
100     if(r->pos+4>r->size) return 0;
101     U32 val = r->mem[r->pos]<<24|
102               r->mem[r->pos+1]<<16|
103               r->mem[r->pos+2]<<8|
104               r->mem[r->pos+3];
105     r->pos += 4;
106     return val;
107 }
108 static void readBlock(memreader_t*r, void*dest, int len)
109 {
110     int remaining = r->size-r->pos;
111     if(len > remaining) {
112         memcpy(dest, r->mem+r->pos, remaining);
113         memset(dest+remaining, 0, len - remaining);
114         r->pos += remaining;
115     } else {
116         memcpy(dest, r->mem+r->pos, len);
117         r->pos += len;
118     }
119 }
120 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
121
122 static void expand(ttf_table_t*w, int newsize)
123 {
124     int v1 = (newsize+63)&~63;
125     int v2 = w->len + w->len / 2;
126     w->memsize = v1>v2?v1:v2;
127     w->data = rfx_realloc(w->data, w->memsize);
128 }
129 static inline void writeU8(ttf_table_t*w, unsigned char b)
130 {
131     if(w->memsize<w->len+1)
132         expand(w, w->len+1);
133     w->data[w->len++] = b;
134 }
135 static inline void writeU16(ttf_table_t*w, unsigned short v)
136 {
137     if(w->memsize<w->len+2)
138         expand(w, w->len+2);
139     w->data[w->len++] = v>>8;
140     w->data[w->len++] = v;
141 }
142 #define writeS16 writeU16
143 static inline void writeU32(ttf_table_t*w, unsigned long v)
144 {
145     if(w->memsize<w->len+4)
146         expand(w, w->len+4);
147     w->data[w->len++] = v>>24;
148     w->data[w->len++] = v>>16;
149     w->data[w->len++] = v>>8;
150     w->data[w->len++] = v;
151 }
152 static inline void writeBlock(ttf_table_t*w, void*data, int len)
153 {
154     if(w->memsize<w->len+len)
155         expand(w, w->len+len);
156     memcpy(w->data+w->len, data, len);
157     w->len += len;
158 }
159
160 ttf_table_t*ttf_table_new(U32 id)
161 {
162     ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
163     t->id = id;
164     return t;
165 }
166
167 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
168 {
169     ttf_table_t*t = ttf_table_new(id);
170
171     ttf_table_t*before,*after=0;
172     for(before=ttf->tables; before&&before->id<id; before=before->next) {
173         after=before;
174     }
175     if(before && before->id == id) {
176         msg("<error> Error: duplicate table %08x", id);
177         free(before->data);
178         before->data = 0;
179         before->len = 0;
180         return before;
181     }
182     
183     if(!after) {
184         t->next = ttf->tables;
185         ttf->tables = t;
186     } else {
187         t->prev = after;
188         t->next = after->next;
189         after->next = t;
190     }
191     if(t->next)
192         t->next->prev = t;
193     return t;
194 }
195 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
196 {
197     ttf_table_t*table = ttf->tables;
198     while(table) {
199         if(table->id == id) 
200             return table;
201         table = table->next;
202     }
203     return 0;
204 }
205 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
206 {
207     if(ttf && ttf->tables == table) {
208         ttf->tables = table->next;
209     }
210     if(table->prev) 
211         table->prev->next = table->next;
212     if(table->next) 
213         table->next->prev = table->prev;
214     free(table->data);
215     free(table);
216 }
217 U32 ttf_table_checksum(ttf_table_t*t)
218 {
219     U32 checksum = checksum_block(t->data, t->len);
220     if(t->id==TAG_HEAD && t->len>=12) {
221         /* the checksum for the HEAD table is calculated by masking out
222            the checksumadjust field */
223         U32 adjust = t->data[8]<<24|t->data[9]<<16|t->data[10]<<8|t->data[11];
224         checksum -= adjust;
225     }
226     return checksum;
227 }
228 static U8 printable(U8 a)
229 {
230     if(a<32 || a==127) return '.';
231     else return a;
232 }
233 static void hexdump(U8*data, int len, const char*prefix)
234 {
235     int t;
236     char ascii[32];
237     printf("%s    -=> ",prefix);
238     for(t=0;t<len;t++) {
239         printf("%02x ", data[t]);
240         ascii[t&15] = printable(data[t]);
241         if((t && ((t&15)==15)) || (t==len-1))
242         {
243             int s,p=((t)&15)+1;
244             ascii[p] = 0;
245             for(s=p-1;s<16;s++) {
246                 printf("   ");
247             }
248             if(t==len-1)
249                 printf(" %s\n", ascii);
250             else
251                 printf(" %s\n%s    -=> ",ascii,prefix);
252         }
253     }
254 }
255 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
256 {
257     if(!t) return;
258     hexdump(t->data, t->len, prefix);
259 }
260
261 static table_head_t*head_new(ttf_t*ttf)
262 {
263     table_head_t*head = rfx_calloc(sizeof(table_head_t));
264     head->units_per_em = 1024;
265     int t;
266     if(ttf->num_glyphs) {
267         head->xmin = ttf->glyphs[0].xmin;
268         head->ymin = ttf->glyphs[0].ymin;
269         head->xmax = ttf->glyphs[0].xmax;
270         head->ymax = ttf->glyphs[0].ymax;
271         for(t=1;t<ttf->num_glyphs;t++) {
272             if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
273             if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
274             if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
275             if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
276         }
277     }
278     head->macStyle = 0;
279     head->lowest_readable_size = 8; // not sure what font renderers actually do with this
280     head->dir_hint = 0;
281     return head;
282 }
283 static int head_parse(ttf_t*ttf, memreader_t*r)
284 {
285     ttf->head = rfx_calloc(sizeof(table_head_t));
286     U32 version = readU32(r);
287     if(version!=VERSION_1_0) 
288         msg("<warning> Font HEAD has unknown version %08x", version);
289     U32 revision = readU32(r);
290     U32 checksum2 = readU32(r);
291     U32 magic = readU32(r);
292     if(magic!=0x5f0f3cf5) 
293         msg("<warning> Font HEAD has unknown magic number %08x", magic);
294     ttf->head->flags = readU16(r);
295     ttf->head->units_per_em = readU16(r);
296     readU32(r);readU32(r); //created
297     readU32(r);readU32(r); //modified
298     ttf->head->xmin = readU16(r);
299     ttf->head->ymin = readU16(r);
300     ttf->head->xmax = readU16(r);
301     ttf->head->ymax = readU16(r);
302     ttf->head->macStyle = readU16(r);
303     ttf->head->lowest_readable_size = readU16(r); //in pixels
304     ttf->head->dir_hint = readS16(r);
305     int loc_index = readS16(r); //used in 'loca' table
306     if(loc_index>1)
307         msg("<warning> loca index format %d unknown", loc_index);
308     U16 glyph_data_format = readS16(r);
309     if(glyph_data_format!=0)
310         msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
311     if(r->pos < r->size) {
312         msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
313     }
314     return loc_index;
315 }
316 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
317 {
318     writeU32(w, 0x10000);
319     writeU32(w, 0x10000);
320     writeU32(w, 0); //checksum
321     writeU32(w, 0x5f0f3cf5); //magic
322     writeU16(w, ttf->head->flags);
323     writeU16(w, ttf->head->units_per_em);
324     writeU32(w, 0);writeU32(w, 0); //created
325     writeU32(w, 0);writeU32(w, 0); //modified
326     writeU16(w, ttf->head->xmin);
327     writeU16(w, ttf->head->ymin);
328     writeU16(w, ttf->head->xmax);
329     writeU16(w, ttf->head->ymax);
330     writeU16(w, ttf->head->macStyle);
331     writeU16(w, ttf->head->lowest_readable_size);
332     writeS16(w, ttf->head->dir_hint);
333     writeS16(w, loca_size); //loca index size (32 bit)
334     writeS16(w, 0); //glyph data format
335 }
336 static void head_dump(ttf_t*ttf)
337 {
338     printf("head->flags: %d\n", ttf->head->flags);
339     printf("head->units_per_em: %d\n", ttf->head->units_per_em);
340     printf("head->xmin: %d\n", ttf->head->xmin);
341     printf("head->ymin: %d\n", ttf->head->ymin);
342     printf("head->xmax: %d\n", ttf->head->xmax);
343     printf("head->ymax: %d\n", ttf->head->ymax);
344     printf("head->macStyle: %d\n", ttf->head->macStyle);
345     printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
346     printf("head->dir_hint: %d\n", ttf->head->dir_hint);
347 }
348 static void head_delete(ttf_t*ttf)
349 {
350     if(ttf->head) {
351         free(ttf->head);
352         ttf->head=0;
353     }
354 }
355
356 static table_os2_t*os2_new(ttf_t*ttf)
357 {
358     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
359     if(ttf->num_glyphs) {
360         int average_width=0;
361         int t;
362         for(t=0;t<ttf->num_glyphs;t++) {
363             average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
364         }
365         os2->xAvgCharWidth = average_width / ttf->num_glyphs;
366     }
367
368     /* that's what everybody seems to fill in */
369     os2->usWeightClass = 400;
370     os2->usWidthClass = 5;
371    
372     if(ttf->head) {
373         int advance = (ttf->head->xmax - ttf->head->xmin)/2;
374         int height = (ttf->head->xmax - ttf->head->xmin);
375         int ymid = height/2;
376         /* I do believe a sane font rendering engine will actually use
377            the font advance here- the subscript/superscript position will
378            not be the same for each glyph */
379         os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
380         os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
381         os2->ySubscriptXOffset = advance;
382         os2->ySubscriptYOffset = 0;
383         os2->ySuperscriptXOffset = advance;
384         os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
385         os2->yStrikeoutSize = ttf->head->units_per_em / 10;
386         os2->yStrikeoutPosition = ymid;
387         os2->usWinAscent = ttf->head->ymax;
388         os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
389         os2->sxHeight = ymid;
390         os2->sCapHeight = height*2/3;
391     }
392     os2->panose_Weight = 4;
393
394     /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
395        what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
396     os2->ulCharRange[0] = 1;
397     os2->ulCharRange[1] = 0;
398     os2->ulCharRange[2] = 0;
399     os2->ulCharRange[3] = 0;
400     os2->ulCodePageRange1 = 1;
401     os2->ulCodePageRange2 = 0;
402
403     if(ttf->unicode_size) {
404         int min,max;
405         for(min=0;min<ttf->unicode_size;min++)
406             if(ttf->unicode[min]) break;
407         for(max=ttf->unicode_size-1;max>=0;max--)
408             if(ttf->unicode[max]) break;
409         if(min<=max) {
410             os2->fsFirstCharIndex = min;
411             os2->fsLastCharIndex = max;
412         }
413     }
414     os2->sTypoAscender = ttf->ascent;
415     os2->sTypoDescender = ttf->descent;
416     os2->sTypoLineGap = ttf->lineGap;
417
418     os2->usDefaultChar = 0;
419     os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
420     os2->usMaxContext = 0; // we don't use ligatures yet
421     return os2;
422 }
423 static table_os2_t*os2_parse(memreader_t*r)
424 {
425     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
426     U16 version = readU16(r);
427     /* 0 = TrueType 1.5
428        1 = TrueType 1.66
429        2 = OpenType 1.2
430        3 = OpenType 1.4 */
431     if(version!=0 && version!=1 && version!=2 && version!=3)
432         msg("<warning> Unknown OS2 version: %04x", version);
433     os2->xAvgCharWidth = readS16(r);
434     os2->usWeightClass = readU16(r);
435     os2->usWidthClass = readU16(r);
436     readU16(r); //fstype
437     os2->ySubscriptXSize = readU16(r);
438     os2->ySubscriptYSize = readU16(r);
439     os2->ySubscriptXOffset = readU16(r);
440     os2->ySubscriptYOffset = readU16(r);
441     os2->ySuperscriptXSize = readU16(r);
442     os2->ySuperscriptYSize = readU16(r);
443     os2->ySuperscriptXOffset = readU16(r);
444     os2->ySuperscriptYOffset = readU16(r);
445     os2->yStrikeoutSize = readU16(r);
446     os2->yStrikeoutPosition = readU16(r);
447     os2->sFamilyClass = readU16(r);
448     os2->panose_FamilyType = readU8(r);
449     os2->panose_SerifStyle = readU8(r);
450     os2->panose_Weight = readU8(r);
451     os2->panose_Proportion = readU8(r);
452     os2->panose_Contrast = readU8(r);
453     os2->panose_StrokeVariation = readU8(r);
454     os2->panose_ArmStyle = readU8(r);
455     os2->panose_Letterform = readU8(r);
456     os2->panose_Midline = readU8(r);
457     os2->panose_XHeight = readU8(r);
458     os2->ulCharRange[0] = readU32(r);
459     os2->ulCharRange[1] = readU32(r);
460     os2->ulCharRange[2] = readU32(r);
461     os2->ulCharRange[3] = readU32(r);
462     readU32(r); //vendor
463     os2->fsSelection = readU16(r);
464     os2->fsFirstCharIndex = readU16(r);
465     os2->fsLastCharIndex = readU16(r);
466     os2->sTypoAscender = readS16(r);
467     os2->sTypoDescender = readS16(r);
468     os2->sTypoLineGap = readS16(r);
469     os2->usWinAscent = readU16(r);
470     os2->usWinDescent = readU16(r);
471     if(version<1) return os2;
472     os2->ulCodePageRange1 = readU32(r);
473     os2->ulCodePageRange2 = readU32(r);
474     if(version<2) return os2;
475     os2->sxHeight = readS16(r);
476     os2->sCapHeight = readS16(r);
477     os2->usDefaultChar = readU16(r);
478     os2->usBreakChar = readU16(r);
479     os2->usMaxContext = readU16(r);
480     
481     if(r->pos < r->size) {
482         msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
483     }
484     return os2;
485 }
486 static void os2_write(ttf_t*ttf, ttf_table_t*w)
487 {
488     table_os2_t*os2 = ttf->os2;
489     U16 version=1;
490     if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
491         version=2;
492     }
493     writeU16(w, version);
494     writeS16(w, os2->xAvgCharWidth);
495     writeU16(w, os2->usWeightClass);
496     writeU16(w, os2->usWidthClass);
497     writeU16(w, 0); //fstype
498     writeU16(w, os2->ySubscriptXSize);
499     writeU16(w, os2->ySubscriptYSize);
500     writeU16(w, os2->ySubscriptXOffset);
501     writeU16(w, os2->ySubscriptYOffset);
502     writeU16(w, os2->ySuperscriptXSize);
503     writeU16(w, os2->ySuperscriptYSize);
504     writeU16(w, os2->ySuperscriptXOffset);
505     writeU16(w, os2->ySuperscriptYOffset);
506     writeU16(w, os2->yStrikeoutSize);
507     writeU16(w, os2->yStrikeoutPosition);
508     writeU16(w, os2->sFamilyClass);
509     writeU8(w, os2->panose_FamilyType);
510     writeU8(w, os2->panose_SerifStyle);
511     writeU8(w, os2->panose_Weight);
512     writeU8(w, os2->panose_Proportion);
513     writeU8(w, os2->panose_Contrast);
514     writeU8(w, os2->panose_StrokeVariation);
515     writeU8(w, os2->panose_ArmStyle);
516     writeU8(w, os2->panose_Letterform);
517     writeU8(w, os2->panose_Midline);
518     writeU8(w, os2->panose_XHeight);
519     writeU32(w, os2->ulCharRange[0]);
520     writeU32(w, os2->ulCharRange[1]);
521     writeU32(w, os2->ulCharRange[2]);
522     writeU32(w, os2->ulCharRange[3]);
523     writeU32(w, 0x53434244); //vendor
524     writeU16(w, os2->fsSelection);
525     writeU16(w, os2->fsFirstCharIndex);
526     writeU16(w, os2->fsLastCharIndex);
527     writeS16(w, os2->sTypoAscender);
528     writeS16(w, os2->sTypoDescender);
529     writeS16(w, os2->sTypoLineGap);
530     writeU16(w, os2->usWinAscent);
531     writeU16(w, os2->usWinDescent);
532     if(version<1) return;
533     writeU32(w, os2->ulCodePageRange1);
534     writeU32(w, os2->ulCodePageRange2);
535     if(version<2) return;
536     writeS16(w, os2->sxHeight);
537     writeS16(w, os2->sCapHeight);
538     writeU16(w, os2->usDefaultChar);
539     writeU16(w, os2->usBreakChar);
540     writeU16(w, os2->usMaxContext);
541 }
542 static void os2_dump(ttf_t*ttf)
543 {
544     table_os2_t*os2 = ttf->os2;
545     if(!os2) return;
546     printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
547     printf("os2->usWeightClass: %d\n", os2->usWeightClass);
548     printf("os2->usWidthClass: %d\n", os2->usWidthClass);
549     printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
550     printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
551     printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
552     printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
553     printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
554     printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
555     printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
556     printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
557     printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
558     printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
559     printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
560     printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
561     printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
562     printf("os2->panose_Weight: %d\n", os2->panose_Weight);
563     printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
564     printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
565     printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
566     printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
567     printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
568     printf("os2->panose_Midline: %d\n", os2->panose_Midline);
569     printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
570     printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
571     printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
572     printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
573     printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
574     printf("os2->fsSelection: %d\n", os2->fsSelection);
575     printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
576     printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
577     printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
578     printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
579     printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
580     printf("os2->usWinAscent: %d\n", os2->usWinAscent);
581     printf("os2->usWinDescent: %d\n", os2->usWinDescent);
582     printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
583     printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
584     printf("os2->sxHeight: %d\n", os2->sxHeight);
585     printf("os2->sCapHeight: %d\n", os2->sCapHeight);
586     printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
587     printf("os2->usBreakChar: %d\n", os2->usBreakChar);
588     printf("os2->usMaxContext: %d\n", os2->usMaxContext);
589 }
590 static void os2_delete(ttf_t*ttf)
591 {
592     if(ttf->os2)
593         free(ttf->os2);
594     ttf->os2=0;
595 }
596
597 static table_maxp_t*maxp_new(ttf_t*ttf)
598 {
599     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
600     int t;
601     maxp->maxContours=1;
602     if(ttf->num_glyphs) {
603         int max = 1;
604         for(t=0;t<ttf->num_glyphs;t++) {
605             if(ttf->glyphs[t].num_points>max)
606                 max = ttf->glyphs[t].num_points;
607             int contours = 0;
608             int s;
609             for(s=0;s<ttf->glyphs[t].num_points;s++) {
610                 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
611                     contours++;
612             }
613             if(maxp->maxContours < contours)
614                 maxp->maxContours = contours;
615         }
616         maxp->maxPoints = max;
617
618         /* we don't generate composite glyphs yet */
619         maxp->maxComponentPoints = 0;
620         maxp->maxComponentContours = 0;
621     }
622     return maxp;
623 }
624 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
625 {
626     U32 version = readU32(r);
627     ttf->num_glyphs = readU16(r);
628     /* according to freetype, older fonts (version<0x10000) 
629        apparently only contain the number of glyphs. this is
630        rather rare, though. */
631     if(version<0x10000 && r->size==6) return 0;
632
633     if(r->size<32)
634         msg("<warning> Truncated maxp table (version %d)", version);
635
636     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
637     maxp->maxPoints = readU16(r);
638     maxp->maxContours = readU16(r);
639     maxp->maxComponentPoints = readU16(r);
640     maxp->maxComponentContours = readU16(r);
641     maxp->maxZones = readU16(r);
642     maxp->maxTwilightPoints = readU16(r);
643     maxp->maxStorage = readU16(r);
644     maxp->maxFunctionDefs = readU16(r);
645     maxp->maxInstructionDefs = readU16(r);
646     maxp->maxStackElements = readU16(r);
647     maxp->maxSizeOfInstructions = readU16(r);
648     maxp->maxComponentElements = readU16(r);
649     maxp->maxComponentDepth = readU16(r);
650     return maxp;
651 }
652 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
653 {
654     table_maxp_t*maxp = ttf->maxp;
655     if(!maxp) {
656         /* version 0.5 simplified maxp table */
657         writeU32(w, 0x00005000);
658         writeU16(w, ttf->num_glyphs);
659         return;
660     }
661     writeU32(w, 0x10000); //version
662     writeU16(w, ttf->num_glyphs);
663     writeU16(w, maxp->maxPoints);
664     writeU16(w, maxp->maxContours);
665     writeU16(w, maxp->maxComponentPoints);
666     writeU16(w, maxp->maxComponentContours);
667     writeU16(w, maxp->maxZones);
668     writeU16(w, maxp->maxTwilightPoints);
669     writeU16(w, maxp->maxStorage);
670     writeU16(w, maxp->maxFunctionDefs);
671     writeU16(w, maxp->maxInstructionDefs);
672     writeU16(w, maxp->maxStackElements);
673     writeU16(w, maxp->maxSizeOfInstructions);
674     writeU16(w, maxp->maxComponentElements);
675     writeU16(w, maxp->maxComponentDepth);
676 }
677 static void maxp_dump(ttf_t*ttf)
678 {
679     table_maxp_t*maxp = ttf->maxp;
680     if(!maxp) return;
681     printf("maxp->maxPoints: %d\n", maxp->maxPoints);
682     printf("maxp->maxContours: %d\n", maxp->maxContours);
683     printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
684     printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
685     printf("maxp->maxZones: %d\n", maxp->maxZones);
686     printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
687     printf("maxp->maxStorage: %d\n", maxp->maxStorage);
688     printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
689     printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
690     printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
691     printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
692     printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
693     printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
694 }
695 static void maxp_delete(ttf_t*ttf)
696 {
697     if(ttf->maxp)
698         free(ttf->maxp);
699     ttf->maxp=0;
700 }
701
702 static table_hea_t*hea_new(ttf_t*ttf)
703 {
704     table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
705     if(ttf->num_glyphs) {
706         int t;
707         for(t=0;t<ttf->num_glyphs;t++) {
708             if(ttf->glyphs[t].advance > hea->advanceWidthMax)
709                 hea->advanceWidthMax = ttf->glyphs[t].advance;
710             if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
711                 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
712             if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
713                 hea->minRightSideBearing = ttf->glyphs[t].xmax;
714             int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
715             if(width > hea->xMaxExtent)
716                 hea->xMaxExtent = width;
717         }
718         /* TODO: caret */
719     }
720     return hea;
721 }
722 static int hea_parse(memreader_t*r, ttf_t*ttf)
723 {
724     table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
725     U32 version = readU32(r);
726     ttf->ascent = readS16(r);
727     ttf->descent = readS16(r);
728     ttf->lineGap = readS16(r);
729     hea->advanceWidthMax = readU16(r);
730     hea->minLeftSideBearing = readS16(r);
731     hea->minRightSideBearing = readS16(r);
732     hea->xMaxExtent = readS16(r);
733     hea->caretSlopeRise = readS16(r);
734     hea->caretSlopeRun = readS16(r);
735     hea->caretOffset = readS16(r);
736     readS16(r); //reserved[0]
737     readS16(r); //reserved[1]
738     readS16(r); //reserved[2]
739     readS16(r); //reserved[3]
740     S16 metricDataFormat = readS16(r); //should be 0
741     if(metricDataFormat!=0) {
742         msg("<warning> Unknown metric format %d", metricDataFormat);
743     }
744     int num_advances = readU16(r);
745     if(num_advances > ttf->num_glyphs) {
746         msg("<warning> bad number of horizontal metrics: %d", num_advances);
747         num_advances = ttf->num_glyphs;
748     }
749     return num_advances;
750 }
751 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
752 {
753     table_hea_t*hea = ttf->hea;
754     writeU32(w, 0x00010000);
755     writeS16(w, ttf->ascent);
756     writeS16(w, ttf->descent);
757     writeS16(w, ttf->lineGap);
758     writeU16(w, hea->advanceWidthMax);
759     writeS16(w, hea->minLeftSideBearing);
760     writeS16(w, hea->minRightSideBearing);
761     writeS16(w, hea->xMaxExtent);
762     writeS16(w, hea->caretSlopeRise);
763     writeS16(w, hea->caretSlopeRun);
764     writeS16(w, hea->caretOffset);
765     writeS16(w, 0); //reserved
766     writeS16(w, 0); //reserved
767     writeS16(w, 0); //reserved
768     writeS16(w, 0); //reserved
769     writeS16(w, 0); //metricDataFormat
770     writeU16(w, num_advances);
771     return hea;
772 }
773 static void hea_dump(ttf_t*ttf)
774 {
775     table_hea_t*hea = ttf->hea;
776     if(!hea) return;
777     const char*dir = ttf->is_vertical?"v":"h";
778     printf("%shea->ascent: %d\n", dir, ttf->ascent);
779     printf("%shea->descent: %d\n", dir, ttf->descent);
780     printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
781     printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
782     printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
783     printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
784     printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
785     printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
786     printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
787     printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
788 }
789 static void hea_delete(ttf_t*ttf)
790 {
791     if(ttf->hea) {
792         free(ttf->hea);
793         ttf->hea=0;
794     }
795 }
796
797 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
798 {
799     U16 old_advance = 0;
800     int t;
801     if(num_advances > r->size/4)
802         num_advances = r->size/4;
803     for(t=0;t<num_advances;t++) {
804         old_advance = ttf->glyphs[t].advance = readU16(r);
805         ttf->glyphs[t].bearing = readS16(r);
806     }
807     int rest = (r->size - num_advances*4)/2;
808     if(ttf->num_glyphs < num_advances+rest) {
809         rest = ttf->num_glyphs-num_advances;
810     }
811     for(t=0;t<rest;t++) {
812         ttf->glyphs[t].advance = old_advance; 
813         ttf->glyphs[t].bearing = readS16(r);
814     }
815 }
816 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
817 {
818     int num_advances = ttf->num_glyphs;
819     if(ttf->num_glyphs>=2) {
820         int t;
821         for(t=ttf->num_glyphs-1;t>0;t--) {
822             if(ttf->glyphs[t-1].advance !=
823                ttf->glyphs[t].advance) break;
824         }
825         /* we need to store all individual advances as well
826            as one entry for the constant */
827         num_advances = t+1;
828     }
829
830     int t;
831     for(t=0;t<num_advances;t++) {
832         writeU16(w, ttf->glyphs[t].advance);
833         writeU16(w, ttf->glyphs[t].bearing);
834     }
835     for(;t<ttf->num_glyphs;t++) {
836         writeU16(w, ttf->glyphs[t].bearing);
837     }
838     return num_advances;
839 }
840
841 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
842 {
843     int t;
844     int num = ttf->num_glyphs+1;
845     U32*locations = rfx_calloc(num*sizeof(U32));
846     U32 lastloc = 0;
847     U32 loc = 0;
848     char warn_unsorted = 1;
849     if(size) {
850         if(num*4 > r->size) {
851             msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
852             num=r->size/4;
853         }
854         if(num*4 < r->size) {
855             msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
856         }
857         for(t=0;t<num;t++) {
858             locations[t] = loc = readU32(r);
859             if(lastloc > loc && warn_unsorted) {
860                 msg("<warning> Unsorted 'loca' table (32 bit)");
861                 warn_unsorted=0;
862             }
863             lastloc = loc;
864         }
865     } else {
866         if(num*2 > r->size) {
867             msg("<warning> Short 'loca' table (16 bit)");
868             num=r->size/2;
869         }
870         if(num*2 < r->size) {
871             msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
872         }
873         for(t=0;t<num;t++) {
874             locations[t] = loc = readU16(r)*2;
875             if(lastloc > loc && warn_unsorted) {
876                 msg("<warning> Unsorted 'loca' table");
877                 warn_unsorted=0;
878             }
879             lastloc = loc;
880         }
881     }
882     return locations;
883 }
884 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
885 {
886     int t;
887     char use_32bit = 0;
888     for(t=0;t<=ttf->num_glyphs;t++) {
889         if(locations[t]>=0x20000 || (locations[t]&1)) {
890             use_32bit = 1;
891             break;
892         }
893     }
894
895     if(use_32bit) {
896         for(t=0;t<=ttf->num_glyphs;t++) {
897             writeU32(w, locations[t]);
898         }
899         return 1;
900     } else {
901         for(t=0;t<=ttf->num_glyphs;t++) {
902             writeU16(w, locations[t]/2);
903         }
904         return 0;
905     }
906 }
907
908 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
909 {
910     ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
911
912     U16*endpoints = 0;
913     if(num_contours>0) {
914         endpoints = malloc(sizeof(U16)*num_contours);
915         int s;
916         int lastpos = -1;
917         for(s=0;s<num_contours;s++) {
918             int pos = endpoints[s] = readU16(r);
919             if(pos<=lastpos) {
920                 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
921             }
922             lastpos = pos;
923         }
924     }
925     U16 code_len = readU16(r);
926     if(code_len) {
927         glyph->code = malloc(sizeof(U16)*code_len);
928         readBlock(r, glyph->code, code_len);
929         glyph->code_size = code_len;
930     }
931
932     if(!endpoints) 
933         return 1;
934
935     /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", 
936             glyphnr, code_len, num_contours, glyph->num_points,
937             xmin, ymin, xmax, ymax);*/
938     INIT_READ(fx, r->mem, r->size, r->pos);
939     INIT_READ(fy, r->mem, r->size, r->pos);
940     
941     glyph->num_points = endpoints[num_contours-1] + 1;
942     glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
943
944     /* parse flag array (1st pass- to determine start of coordinates) */
945     int num=0;
946     while(num<glyph->num_points) {
947         U8 flag = readU8(r);
948         if(flag&0xc0) {
949             msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
950             free(glyph->points);
951             glyph->points = 0;
952             glyph->num_points = 0;
953             return 0;
954         }
955         int count = 1;
956         if(flag & 0x08) 
957             count += readU8(r);
958         if(count+num>glyph->num_points) {
959             msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
960             count = glyph->num_points-num;
961         }
962         num+=count;
963     }
964
965     /* parse flag array (2nd pass) and x coordinates */
966     num=0;
967     int x = 0;
968     char is_start=1;
969     int contour_pos=0;
970     int bytepos = r->pos;
971     while(num<glyph->num_points) {
972         U8 flag = readU8(&fx);
973         int count = flag&8?readU8(&fx)+1:1;
974         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
975         do {
976             char is_end=0;
977             if(contour_pos<num_contours && num==endpoints[contour_pos]) {
978                 contour_pos++;
979                 is_end=1;
980             }
981             int oldx = x;
982             if((flag&0x12) == 0x12) x += readU8(r);
983             else if((flag&0x12) == 0x02) x -= readU8(r);
984             else if((flag&0x12) == 0x00) x += readS16(r);
985             
986             glyph->points[num].x = x;
987             U8 f = flag&GLYPH_ON_CURVE;
988             if(is_start) f|=GLYPH_CONTOUR_START;
989             if(is_end) f|=GLYPH_CONTOUR_END;
990             glyph->points[num].flags = f;
991             num++;
992             is_start = is_end;
993         } while(--count);
994     }
995     
996     /* parse flag array (3rd pass) and y coordinates */
997     num=0;
998     int y = 0;
999     while(num<glyph->num_points) {
1000         U8 flag = readU8(&fy);
1001         int count = flag&8?readU8(&fy)+1:1;
1002         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1003         do {
1004             if((flag&0x24) == 0x24) y += readU8(r);
1005             else if((flag&0x24) == 0x04) y -= readU8(r);
1006             else if((flag&0x24) == 0x00) y += readS16(r);
1007             glyph->points[num].y = y;
1008             num++;
1009         } while(--count);
1010     }
1011     free(endpoints);
1012     return 1;
1013 }
1014 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1015 {
1016     int t;
1017     char warn_about_compound_glyphs=0;
1018     for(t=0;t<ttf->num_glyphs;t++) {
1019         INIT_READ(r, rr->mem, rr->size, loca[t]);
1020         if(loca[t]==loca[t+1] || loca[t]==r.size)
1021             continue; //empty glyph
1022         if(r.pos+10>r.size) {
1023             msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", 
1024                     t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1025             break;
1026         }
1027         S16 num_contours = readS16(&r);
1028         ttf->glyphs[t].xmin = readS16(&r);
1029         ttf->glyphs[t].ymin = readS16(&r);
1030         ttf->glyphs[t].xmax = readS16(&r);
1031         ttf->glyphs[t].ymax = readS16(&r);
1032         
1033         if(num_contours<0) {
1034             if(warn_about_compound_glyphs)
1035                 msg("<error> Compound glyphs not supported yet");
1036             warn_about_compound_glyphs=0;
1037         } else {
1038             if(!parse_simple_glyph(ttf, &r, num_contours, t))
1039                 return;
1040         }
1041     }
1042
1043 }
1044 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1045 {
1046     /* endpoints array */
1047     int s;
1048     for(s=0;s<g->num_points;s++) {
1049         if(g->points[s].flags&GLYPH_CONTOUR_END)
1050             writeU16(w, s);
1051     }
1052     
1053     /* bytecode */
1054     writeU16(w, g->code_size);
1055     if(g->code_size)
1056         writeBlock(w, g->code, g->code_size);
1057
1058     /* flags */
1059     int lastx=0;
1060     int lasty=0;
1061     int lastflag=-1;
1062     int flagcount=0;
1063     for(s=0;s<g->num_points;s++) {
1064         ttfpoint_t*p = &g->points[s];
1065         int dx = p->x - lastx;
1066         int dy = p->y - lasty;
1067         U8 flags = p->flags&GLYPH_ON_CURVE;
1068         if(!dx) {
1069             flags|=0x10;
1070         } else if(dx<0 && dx>=-255) {
1071             flags|=0x02;
1072         } else if(dx>0 && dx<=255) {
1073             flags|=0x12;
1074         }
1075         if(!dy) {
1076             flags|=0x20;
1077         } else if(dy<0 && dy>=-255) {
1078             flags|=0x04;
1079         } else if(dy>0 && dy<=255) {
1080             flags|=0x24;
1081         }
1082         if(flags == lastflag && flagcount<255) {
1083             flagcount++;
1084         } else {
1085             if(lastflag>=0) {
1086                 if(flagcount) {
1087                     writeU8(w, lastflag|8);
1088                     writeU8(w, flagcount);
1089                 } else {
1090                     writeU8(w, lastflag);
1091                 }
1092             }
1093             lastflag = flags;
1094             flagcount = 0;
1095         }
1096         lastx = p->x;
1097         lasty = p->y;
1098     }
1099     if(lastflag>=0) {
1100         if(flagcount) {
1101             writeU8(w, lastflag|8);
1102             writeU8(w, flagcount);
1103         } else {
1104             writeU8(w, lastflag);
1105         }
1106     }
1107     /* coordinates */
1108     lastx=0;
1109     int bytepos = w->len;
1110     for(s=0;s<g->num_points;s++) {
1111         ttfpoint_t*p = &g->points[s];
1112         int dx = p->x - lastx;
1113         if(dx>32767 || dx<-32768) {
1114             msg("<error> Coordinate overflow in glyph");
1115         }
1116         lastx = p->x;
1117         if(dx>0 && dx<=255) writeU8(w, dx);
1118         else if(dx<0 && dx>=-255) writeU8(w, -dx);
1119         else if(dx) writeS16(w, dx);
1120     }
1121
1122     lasty=0;
1123     for(s=0;s<g->num_points;s++) {
1124         ttfpoint_t*p = &g->points[s];
1125         int dy = p->y - lasty;
1126         if(dy>32767 || dy<-32768) {
1127             msg("<error> Coordinate overflow in glyph");
1128         }
1129         lasty = p->y;
1130         if(dy>0 && dy<=255) writeU8(w, dy);
1131         else if(dy<0 && dy>=-255) writeU8(w, -dy);
1132         else if(dy) writeS16(w, dy);
1133     }
1134 }
1135 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1136 {
1137     U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1138     int t;
1139     for(t=0;t<ttf->num_glyphs;t++) {
1140         locations[t] = w->len;
1141         ttfglyph_t*g = &ttf->glyphs[t];
1142         int s;
1143         int num_contours = 0;
1144         for(s=0;s<g->num_points;s++) {
1145             if(g->points[s].flags&GLYPH_CONTOUR_END)
1146                 num_contours++;
1147         }
1148         writeS16(w, num_contours?num_contours:1);
1149         writeS16(w, g->xmin);
1150         writeS16(w, g->ymin);
1151         writeS16(w, g->xmax);
1152         writeS16(w, g->ymax);
1153         
1154         if(!num_contours) {
1155             /* some ttf parsers can't deal with zero contours, so in the case
1156                of an empty glyph, write a single point (0,0) */
1157             writeU16(w, 0); //endpoint of 1st contour
1158             writeU16(w, g->code_size);
1159             if(g->code_size)
1160                 writeBlock(w, g->code, g->code_size);
1161             writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1162         } else {
1163             write_simple_glyph(w, g);
1164         }
1165     }
1166     locations[t] = w->len;
1167     return locations;
1168 }
1169 void glyf_dump(ttf_t* ttf)
1170 {
1171     if(!ttf->glyphs) return;
1172     int t;
1173     for(t=0;t<ttf->num_glyphs;t++) {
1174         ttfglyph_t*g = &ttf->glyphs[t];
1175         printf("glyph %d)\n", t);
1176         printf("  advance=%d\n", g->advance);
1177         printf("  bearing=%d\n", g->bearing);
1178         printf("  bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1179         printf("  points=(");
1180         int s;
1181         for(s=0;s<g->num_points;s++) {
1182             if(s) printf(",");
1183             printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1184         }
1185         printf(")\n");
1186         if(g->code_size) 
1187             hexdump(g->code, g->code_size, "  ");
1188     }
1189 }
1190 void glyf_delete(ttf_t* ttf)
1191 {
1192     if(!ttf->glyphs) 
1193         return;
1194     int t;
1195     for(t=0;t<ttf->num_glyphs;t++) {
1196         if(ttf->glyphs[t].code) {
1197             free(ttf->glyphs[t].code);
1198             ttf->glyphs[t].code = 0;
1199         }
1200         if(ttf->glyphs[t].points) {
1201             free(ttf->glyphs[t].points);
1202             ttf->glyphs[t].points = 0;
1203         }
1204     }
1205     free(ttf->glyphs);ttf->glyphs=0;
1206 }
1207
1208 static void grow_unicode(ttf_t*ttf, int index)
1209 {
1210     int size = index+1;
1211     if(!ttf->unicode) {
1212         ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1213     } else if(ttf->unicode_size<size) {
1214         ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1215         memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1216     }
1217     ttf->unicode_size = size;
1218 }
1219 void cmap_parse(memreader_t*r, ttf_t*ttf)
1220 {
1221     readU16(r); // version (0)
1222     int num_subtables = readU16(r);
1223     int t;
1224     char warn=1;
1225     if(r->pos+num_subtables*8 > r->size) {
1226         msg("<warning> CMap overflow");
1227         num_subtables = (r->size-r->pos)/8;
1228     }
1229     unicode_t*data = 0;
1230     for(t=0;t<num_subtables;t++) {
1231         U16 platform = readU16(r);
1232         U16 encoding = readU16(r);
1233         U32 offset = readU32(r);
1234         if(offset>r->size) {
1235             msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1236             continue;
1237         }
1238
1239         int is_unicode = platform==0 ||
1240                          platform==3 && encoding == 1 ||
1241                          platform==3 && encoding == 10;
1242
1243         if(!is_unicode) 
1244             continue;
1245
1246         INIT_READ(t, r->mem, r->size, offset);
1247         U16 format = readU16(&t);
1248         int length = readU16(&t);
1249         U16 language = readU16(&t);
1250
1251         if(language)
1252             msg("<warning> Language code %02x in unicode mapping", language);
1253
1254         int num = 0;
1255         if(format == 0) {
1256             num = length-6;
1257             if(t.pos+length > t.size) {
1258                 msg("<warning> overflow in format 0 cmap table");
1259                 num = t.size-t.pos;
1260             }
1261             data = malloc(num*sizeof(unicode_t));
1262             int s;
1263             grow_unicode(ttf, num);
1264             for(s=0;s<num;s++) {
1265                 ttf->unicode[s] = readU8(&t);
1266             }
1267         } else if(format == 4) {
1268             U16 segment_count = readU16(&t); 
1269             if(segment_count&1) {
1270                 msg("<error> Bad segmentx2 count %d", segment_count);
1271                 continue;
1272             }
1273             segment_count>>=1;
1274             readU16(&t); //searchrange
1275             readU16(&t); //entry selector
1276             readU16(&t); //range shift
1277             INIT_READ(r_end, t.mem, t.size, t.pos);
1278             INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1279             INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1280             INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1281             int glyphmap_start = t.pos+2+segment_count*8;
1282             int glyphmap_size = t.size - glyphmap_start;
1283             int s;
1284             for(s=0;s<segment_count;s++) {
1285                 U16 start = readU16(&r_start);
1286                 U16 end = readU16(&r_end);
1287                 U16 delta = readU16(&r_delta);
1288                 U16 range = readU16(&r_range);
1289                 if(start==0xffff && end==0xffff && delta==1) {
1290                     /* this is a common (maybe even required) occurence in fonts 
1291                        which explicitly map "unicode undefined" (0xffff) to 
1292                        "glyph undefined" (0).
1293                        We don't want to blow our unicode table up to 65536 just
1294                        because of this, so ignore this entry.
1295                      */
1296                     continue;
1297                 }
1298                 grow_unicode(ttf, end);
1299                 int u;
1300                 if(!range) {
1301                     for(u=start;u<=end;u++) {
1302                         ttf->unicode[u] = (u + delta) & 0xffff;
1303                     }
1304                 } else {
1305                     int pos = r_range.pos-2+range;
1306                     if(warn && pos+end-start+1 > t.size) {
1307                         msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1308                         warn=0;
1309                     }
1310                     INIT_READ(g, t.mem, t.size, pos);
1311                     for(u=start;u<=end;u++) {
1312                         ttf->unicode[u] = readU16(&g);
1313                     }
1314                 }
1315             }
1316         }
1317     }
1318 }
1319 static int segment_size(unicode_t*unicode, int pos, int size)
1320 {
1321     int s;
1322     int count=0;
1323     for(s=pos;s<size;s++) {
1324         if(!unicode[s])
1325             count++;
1326         if(count>4) {
1327             /* a segment costs us 8 bytes, so for more than 4 consecutive 
1328                zero entries (16 bit each) in the glyph index array,
1329                it pays off to start a new segment */
1330             break;
1331         }
1332     }
1333     s -= count; // go to the last filled in entry
1334     if(s==size)
1335         return size-1;
1336     return s;
1337 }
1338 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1339 {
1340     writeU16(w, 0);  //version
1341     writeU16(w, 2);  //two tables
1342
1343     writeU16(w, 0);  //platform (unicode)
1344     writeU16(w, 3);  //encoding (unicode 2.0)
1345     writeU32(w, 20); //offset
1346
1347     writeU16(w, 3);  //platform (windows)
1348     writeU16(w, 1);  //encoding (unicode basic multilingual plane UCS-2)
1349     writeU32(w, 20); //offset
1350
1351     writeU16(w, 4); // format=4
1352     int length_pos = w->len;
1353     writeU16(w, 0); // length: we don't know yet
1354     writeU16(w, 0); // language (n/a for unicode)
1355     int num_segments_pos = w->len;
1356     writeU16(w, 0); //number of segments: we don't know yet either
1357     writeU16(w, 0); //searchrange
1358     writeU16(w, 0); //entry selector
1359     writeU16(w, 0); //range shift
1360
1361     int pos=0;
1362     int num_segments=0;
1363     while(pos < ttf->unicode_size) {
1364         if(!ttf->unicode[pos]) {
1365             pos++;
1366             continue;
1367         }
1368         int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1369         pos = s+1;
1370         num_segments++;
1371     }
1372
1373     num_segments++; // account for 0xffff mapping
1374
1375     int glyphmap_start = w->len+2+num_segments*8;
1376     
1377     int t;
1378     int end_pos = w->len;
1379     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1380     writeU16(w, 0); //reserved byte
1381     int start_pos = w->len;
1382     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1383     int delta_pos = w->len;
1384     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1385     int range_pos = w->len;
1386     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1387             
1388     w->data[num_segments_pos]=(num_segments*2)>>8;
1389     w->data[num_segments_pos+1]=(num_segments*2);
1390     
1391     pos=0;
1392     num_segments = 0;
1393     while(pos < ttf->unicode_size) {
1394         if(!ttf->unicode[pos]) {
1395             pos++;
1396             continue;
1397         }
1398         U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1399         w->data[end_pos++]=end>>8;
1400         w->data[end_pos++]=end;
1401         w->data[start_pos++]=pos>>8;
1402         w->data[start_pos++]=pos;
1403         int s;
1404         U16 delta = ttf->unicode[pos]-pos;
1405         char do_delta=1;
1406         for(s=pos+1;s<=end;s++) {
1407             U16 delta2 = ttf->unicode[s]-s;
1408             if(delta2!=delta) {
1409                 do_delta=0;
1410                 break;
1411             }
1412         }
1413         U16 range;
1414         if(do_delta) {
1415             range = 0;
1416         } else {
1417             delta = 0;
1418             range = w->len - range_pos;
1419             for(s=pos;s<=end;s++) {
1420                 writeU16(w, ttf->unicode[s]);
1421             }
1422         }
1423         w->data[delta_pos++]=delta>>8;
1424         w->data[delta_pos++]=delta;
1425         w->data[range_pos++]=range>>8;
1426         w->data[range_pos++]=range;
1427         num_segments++;
1428         pos = end+1;
1429     }
1430
1431     /* write out a mapping from 0xffff to 0- seems to be required
1432        by some libraries (e.g. fonttools) */
1433     w->data[end_pos++]=0xff;
1434     w->data[end_pos++]=0xff;
1435     w->data[start_pos++]=0xff;
1436     w->data[start_pos++]=0xff;
1437     w->data[delta_pos++]=0;
1438     w->data[delta_pos++]=1;
1439     w->data[range_pos++]=0;
1440     w->data[range_pos++]=0;
1441
1442     w->data[length_pos]=(w->len-20)>>8;
1443     w->data[length_pos+1]=w->len-20;
1444 }
1445 void cmap_delete(ttf_t*ttf)
1446 {
1447     if(ttf->unicode) {
1448         free(ttf->unicode);
1449         ttf->unicode=0;
1450     }
1451     ttf->unicode_size=0;
1452 }
1453 void name_parse(memreader_t*r, ttf_t*ttf)
1454 {
1455     U16 format = readU16(r);
1456     U16 count = readU16(r);
1457     U16 offset = readU16(r);
1458    
1459     int t;
1460     for(t=0;t<count;t++) {
1461         U16 platform = readU16(r);
1462         U16 encoding = readU16(r);
1463         U16 language = readU16(r);
1464         U16 name_id = readU16(r);
1465         U16 len = readU16(r);
1466         U16 offset_2 = readU16(r);
1467         if(name_id==4) {
1468             if(ttf->name)
1469                 free(ttf->name);
1470             ttf->name = strdup_n(&r->mem[offset+offset_2], len);
1471         }
1472     }
1473 }
1474 void name_write(ttf_t*ttf, ttf_table_t*table)
1475 {
1476     writeU16(table, 0); //format
1477     writeU16(table, 1); //count
1478     int offset = 18;
1479     writeU16(table, offset); //offset
1480
1481     writeU16(table, 1); //platform id
1482     writeU16(table, 0); //encoding id
1483     writeU16(table, 0); //language
1484     writeU16(table, 4); //4: full name
1485     int len = strlen(ttf->name);
1486     writeU16(table, len);
1487     writeU16(table, table->len+2 - offset);
1488     int t;
1489     for(t=0;t<len;t++) {
1490         writeU8(table, ttf->name[t]);
1491     }
1492 }
1493 void name_delete(ttf_t*ttf)
1494 {
1495     if(ttf->name) {
1496         free(ttf->name);
1497         ttf->name=0;
1498     }
1499 }
1500
1501 static table_post_t*post_new(ttf_t*ttf)
1502 {
1503     table_post_t*post = rfx_calloc(sizeof(table_post_t));
1504     return post;
1505 }
1506 void post_parse(memreader_t*r, ttf_t*ttf)
1507 {
1508     table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1509     U16 format = readU16(r);
1510     post->italic_angle = readU16(r);
1511     post->underline_position = readU16(r);
1512     post->underline_thickness = readU16(r);
1513     U16 is_monospaced = readU16(r);
1514     readU16(r); // min mem 42
1515     readU16(r);
1516     readU16(r); // min mem 1
1517     readU16(r);
1518 }
1519 void post_write(ttf_t*ttf, ttf_table_t*table)
1520 {
1521     table_post_t*post = ttf->post;
1522     writeU32(table, 0x00030000);
1523     writeU32(table, post->italic_angle);
1524     writeU16(table, post->underline_position);
1525     writeU16(table, post->underline_thickness);
1526     writeU32(table, 0); //is monospaced TODO
1527     writeU32(table, 0); //min mem 42
1528     writeU32(table, 0);
1529     writeU32(table, 0); //min mem 1
1530     writeU32(table, 0);
1531 }
1532 void post_delete(ttf_t*ttf)
1533 {
1534     if(ttf->post) {
1535         free(ttf->post);
1536         ttf->post = 0;
1537     }
1538 }
1539
1540 static int ttf_parse_tables(ttf_t*ttf)
1541 {
1542     ttf_table_t*table;
1543
1544     table = ttf_find_table(ttf, TAG_HEAD);
1545     if(!table) {
1546         msg("<error> Font has no head table");
1547         return 0;
1548     }
1549     INIT_READ(m, table->data, table->len, 0);
1550     int loc_index = head_parse(ttf, &m);
1551     ttf_table_delete(ttf, table);
1552     
1553     table = ttf_find_table(ttf, TAG_MAXP);
1554     if(!table) {
1555         msg("<error> Font has no maxp table");
1556         return 0;
1557     }
1558     INIT_READ(m2, table->data, table->len, 0);
1559     ttf->maxp = maxp_parse(ttf, &m2);
1560     ttf_table_delete(ttf, table);
1561     
1562     if(!ttf->num_glyphs) {
1563         msg("<error> Invalid number of characters");
1564         return 0;
1565     }
1566     ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1567
1568     table = ttf_find_table(ttf, TAG_OS2);
1569     if(table) {
1570         INIT_READ(m, table->data, table->len, 0);
1571         ttf->os2 = os2_parse(&m);
1572         ttf_table_delete(ttf, table);
1573     }
1574
1575     table = ttf_find_table(ttf, TAG_HHEA);
1576     if(table) {
1577         INIT_READ(m, table->data, table->len, 0);
1578         int num_advances = hea_parse(&m, ttf);
1579         ttf_table_delete(ttf, table);
1580         
1581         table = ttf_find_table(ttf, TAG_HMTX);
1582         if(table) {
1583             INIT_READ(m, table->data, table->len, 0);
1584             mtx_parse(&m, ttf, num_advances);
1585             ttf_table_delete(ttf, table);
1586         }
1587     } else {
1588         table = ttf_find_table(ttf, TAG_VHEA);
1589         if(table) {
1590             ttf->is_vertical=1;
1591             INIT_READ(m, table->data, table->len, 0);
1592             int num_advances = hea_parse(&m, ttf);
1593             ttf_table_delete(ttf, table);
1594
1595             table = ttf_find_table(ttf, TAG_VMTX);
1596             if(table) {
1597                 INIT_READ(m, table->data, table->len, 0);
1598                 mtx_parse(&m, ttf, num_advances);
1599                 ttf_table_delete(ttf, table);
1600             }
1601         } else {
1602             msg("<error> Font contains neither HHEA nor VHEA");
1603         }
1604     }
1605     table = ttf_find_table(ttf, TAG_LOCA);
1606     if(table) {
1607         INIT_READ(m, table->data, table->len, 0);
1608         U32*loca = loca_parse(&m, ttf, loc_index);
1609         ttf_table_delete(ttf, table);
1610         table = ttf_find_table(ttf, TAG_GLYF);
1611         if(table) {
1612             INIT_READ(m, table->data, table->len, 0);
1613             glyf_parse(&m, ttf, loca);
1614             ttf_table_delete(ttf, table);
1615         }
1616         free(loca);
1617     }
1618     
1619     table = ttf_find_table(ttf, TAG_CMAP);
1620     if(table) {
1621         INIT_READ(m, table->data, table->len, 0);
1622         cmap_parse(&m, ttf);
1623         ttf_table_delete(ttf, table);
1624     }
1625     
1626     table = ttf_find_table(ttf, TAG_NAME);
1627     if(table) {
1628         INIT_READ(m, table->data, table->len, 0);
1629         name_parse(&m, ttf);
1630         ttf_table_delete(ttf, table);
1631     }
1632
1633     table = ttf_find_table(ttf, TAG_POST);
1634     if(table) {
1635         INIT_READ(m, table->data, table->len, 0);
1636         post_parse(&m, ttf);
1637         ttf_table_delete(ttf, table);
1638     }
1639
1640     return 1;
1641 }
1642 static void ttf_collapse_tables(ttf_t*ttf)
1643 {
1644     ttf_table_t*table;
1645    
1646     table = ttf_addtable(ttf, TAG_MAXP);
1647     maxp_write(ttf, table);
1648     maxp_delete(ttf);
1649
1650     table = ttf_addtable(ttf, TAG_OS2);
1651     os2_write(ttf, table);
1652     os2_delete(ttf);
1653
1654     if(!ttf->is_vertical) {
1655         table = ttf_addtable(ttf, TAG_HMTX);
1656         int num_advances = mtx_write(ttf, table);
1657         table = ttf_addtable(ttf, TAG_HHEA);
1658         hea_write(ttf, table, num_advances);
1659     } else {
1660         table = ttf_addtable(ttf, TAG_VMTX);
1661         int num_advances = mtx_write(ttf, table);
1662         table = ttf_addtable(ttf, TAG_VHEA);
1663         hea_write(ttf, table, num_advances);
1664     }
1665         
1666     int loca_size=0;
1667     if(ttf->num_glyphs) {
1668         table = ttf_addtable(ttf, TAG_CMAP);
1669         cmap_write(ttf, table);
1670         cmap_delete(ttf);
1671
1672         table = ttf_addtable(ttf, TAG_GLYF);
1673         U32*locations = glyf_write(ttf, table);
1674         glyf_delete(ttf);
1675         
1676         table = ttf_addtable(ttf, TAG_LOCA);
1677         loca_size = loca_write(ttf, table, locations);
1678         free(locations);
1679     }
1680
1681     if(ttf->name) {
1682         table = ttf_addtable(ttf, TAG_NAME);
1683         name_write(ttf, table);
1684         name_delete(ttf);
1685     }
1686     if(ttf->post) {
1687         table = ttf_addtable(ttf, TAG_POST);
1688         post_write(ttf, table);
1689         post_delete(ttf);
1690     }
1691     
1692     table = ttf_addtable(ttf, TAG_HEAD);
1693     head_write(ttf, table, loca_size);
1694     head_delete(ttf);
1695 }
1696
1697 ttf_t*ttf_new()
1698 {
1699     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1700     ttf->version = VERSION_1_0;
1701     return ttf;
1702 }
1703 ttf_t* ttf_load(void*data, int length)
1704 {
1705     INIT_READ(r,data,length, 0);
1706
1707     if(length<12) {
1708         msg("<error> Truncated Truetype file (%d bytes)", length);
1709         return 0;
1710     }
1711
1712     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1713     ttf->version = readU32(&r);
1714     if(ttf->version == TTCFTAG) {
1715         /* a ttc collection is a number of truetype fonts
1716            packaged together */
1717         if(length<16) {
1718             msg("<error> Truncated TTC file (%d bytes)", length);
1719             return 0;
1720         }
1721         U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1722         U32 num_fonts = readU32(&r); // number of fonts
1723         U32 font1_position = readU32(&r);
1724         if(font1_position+12 > length) {\
1725             msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1726             return 0;
1727         }
1728         r.pos = font1_position;
1729         ttf->version = readU32(&r);
1730     }
1731     
1732     int num_tables = readU16(&r);
1733     
1734     readU16(&r); //search range
1735     readU16(&r); //entry selector
1736     readU16(&r); //range shift
1737
1738     if(num_tables*16 > length) {
1739         msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1740         if(ttf->version != OPENTYPE && 
1741            ttf->version != TRUETYPE_MACOS && 
1742            ttf->version != VERSION_1_0) {
1743             // bad table length, weird version. This is probably not a ttf file.
1744             return 0;
1745         }
1746     }
1747
1748     U32*table_data = malloc(16*num_tables);
1749     int t;
1750     for(t=0;t<num_tables*4;t++) {
1751         table_data[t] = readU32(&r);
1752     }
1753     for(t=0;t<num_tables;t++) {
1754         U32 tag = table_data[t*4];
1755         U32 checksum = table_data[t*4+1];
1756         U32 pos = table_data[t*4+2];
1757         U32 len = table_data[t*4+3];
1758
1759         if(pos+len > length) {
1760             msg("<error> TTF Table %02x%02x%02x%02x outside of stream (pos %d)", (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, pos);
1761         } else {
1762             U8*mem = malloc(len);
1763             r.pos = pos;
1764             readBlock(&r, mem, len);
1765             
1766             ttf_table_t*table = ttf_addtable(ttf, tag);
1767             table->data = mem;
1768             table->len = table->memsize = len;
1769 #if 0
1770             U32 checksum2 = ttf_table_checksum(table);
1771             if(checksum2!=checksum) {
1772                 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
1773                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1774                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1775                         len, checksum2, checksum);
1776             }
1777 #endif
1778         }
1779     }
1780     free(table_data);
1781
1782     if(!ttf_parse_tables(ttf)) 
1783         return 0;
1784
1785     return ttf;
1786 }
1787 void ttf_create_truetype_tables(ttf_t*ttf)
1788 {
1789     if(!ttf->head) 
1790         ttf->head = head_new(ttf);
1791     if(!ttf->maxp) 
1792         ttf->maxp = maxp_new(ttf);
1793     if(!ttf->hea)
1794         ttf->hea = hea_new(ttf);
1795     if(!ttf->os2)
1796         ttf->os2 = os2_new(ttf);
1797     if(!ttf->post)
1798         ttf->post = post_new(ttf);
1799 }
1800 ttf_table_t* ttf_write(ttf_t*ttf)
1801 {
1802     ttf_collapse_tables(ttf);
1803    
1804     ttf_table_t*file = ttf_table_new(0);
1805     writeU32(file, VERSION_1_0);
1806
1807     /* write number of tables */
1808     int num_tables=0;
1809     ttf_table_t*t = ttf->tables;
1810     while(t) {
1811         num_tables++;
1812         t = t->next;
1813     }
1814     writeU16(file, num_tables);
1815     
1816     /* write search range */
1817     int tmp = num_tables;
1818     int search_range = 0;
1819     while(tmp) {
1820         search_range = tmp;
1821         tmp = tmp&(tmp-1);
1822     }
1823     tmp = search_range;
1824     search_range*=16;
1825     writeU16(file, search_range);
1826
1827     /* write entry selector */
1828     int entry_selector = 0;
1829     while(tmp>1) {
1830         tmp>>=1;
1831         entry_selector++;
1832     }
1833     writeU16(file, entry_selector);
1834
1835     /* write range shift */
1836     int range_shift = num_tables*16 - search_range;
1837     writeU16(file, range_shift);
1838
1839     /* write table dictionary */
1840     int table_dictionary_pos = file->len;
1841     int data_pos = file->len + num_tables*16;
1842     for(t=ttf->tables;t;t=t->next) {
1843         writeU32(file, t->id);
1844         writeU32(file, ttf_table_checksum(t));
1845         writeU32(file, data_pos);
1846         writeU32(file, t->len);
1847         data_pos += t->len;
1848         data_pos += (-t->len)&3; //pad
1849     }
1850
1851     /* write tables */
1852     int head_pos = 0;
1853     U8 zero[4]={0,0,0,0};
1854     for(t=ttf->tables;t;t=t->next) {
1855         if(t->id == TAG_HEAD)
1856             head_pos = file->len;
1857         writeBlock(file, t->data, t->len);
1858         writeBlock(file, zero, (-t->len)&3); //pad
1859     }
1860     U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1861     U8*checksum2 = file->data + head_pos + 8;
1862     checksum2[0] = checksum>>24;
1863     checksum2[1] = checksum>>16;
1864     checksum2[2] = checksum>>8;
1865     checksum2[3] = checksum>>0;
1866     return file;
1867 }
1868 void ttf_save(ttf_t*ttf, const char*filename)
1869 {
1870     ttf_table_t* t = ttf_write(ttf);
1871     FILE*fi = fopen(filename, "wb");
1872     if(!fi) {
1873         perror(filename);
1874         return;
1875     }
1876     fwrite(t->data, t->len, 1, fi);
1877     fclose(fi);
1878     ttf_table_delete(0, t);
1879 }
1880 void ttf_dump(ttf_t*ttf)
1881 {
1882     msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1883     ttf_table_t*table = ttf->tables;
1884     while(table) {
1885         U32 tag = table->id;
1886         msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", 
1887                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, 
1888                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1889         table = table->next;
1890     }
1891     //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1892
1893     head_dump(ttf);
1894     hea_dump(ttf);
1895     os2_dump(ttf);
1896     maxp_dump(ttf);
1897     glyf_dump(ttf);
1898 }
1899 void ttf_destroy_tables(ttf_t*ttf)
1900 {
1901     ttf_table_t*table = ttf->tables;
1902     while(table) {
1903         ttf_table_t*next = table->next;
1904         free(table->data);
1905         free(table);
1906         table = next;
1907     }
1908     ttf->tables = 0;
1909 }
1910 void ttf_reduce(ttf_t*ttf)
1911 {
1912     ttf_destroy_tables(ttf);
1913 }
1914 void ttf_destroy(ttf_t*ttf)
1915 {
1916     ttf_destroy_tables(ttf);
1917     maxp_delete(ttf);
1918     os2_delete(ttf);
1919     head_delete(ttf);
1920     hea_delete(ttf);
1921     glyf_delete(ttf);
1922     post_delete(ttf);
1923     name_delete(ttf);
1924     free(ttf);
1925 }
1926
1927 #ifdef MAIN
1928 int main(int argn, const char*argv[])
1929 {
1930     setConsoleLogging(7);
1931     const char*filename = "comic.ttf";
1932     if(argn>1) 
1933         filename = argv[1];
1934     //msg("<notice> Loading %s", filename);
1935     memfile_t*m = memfile_open(filename);
1936     ttf_t*ttf = ttf_load(m->data, m->len);
1937     if(!ttf) {
1938         msg("<error> Couldn't load %s", filename);
1939         return 1;
1940     }
1941     ttf_reduce(ttf);
1942     ttf->name = strdup("testfont");
1943     if(!ttf) return 1;
1944     memfile_close(m);
1945     //ttf_dump(ttf);
1946     //printf("os2 version: %04x (%d), maxp size: %d\n", 
1947 //          ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1948     ttf_save(ttf, "testfont.ttf");
1949     ttf_destroy(ttf);
1950     return 0;
1951
1952 }
1953 #endif