fixed bugs in ttf writer
[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     if(ttf->num_glyphs) {
602         int max = 0;
603         for(t=0;t<ttf->num_glyphs;t++) {
604             if(ttf->glyphs[t].num_points>max)
605                 max = ttf->glyphs[t].num_points;
606             int contours = 0;
607             int s;
608             for(s=0;s<ttf->glyphs[t].num_points;s++) {
609                 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
610                     contours++;
611             }
612             if(maxp->maxContours < contours)
613                 maxp->maxContours = contours;
614         }
615         maxp->maxPoints = max;
616
617         /* we don't generate composite glyphs yet */
618         maxp->maxComponentPoints = 0;
619         maxp->maxComponentContours = 0;
620     }
621     return maxp;
622 }
623 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
624 {
625     U32 version = readU32(r);
626     ttf->num_glyphs = readU16(r);
627     /* according to freetype, older fonts (version<0x10000) 
628        apparently only contain the number of glyphs. this is
629        rather rare, though. */
630     if(version<0x10000 && r->size==6) return 0;
631
632     if(r->size<32)
633         msg("<warning> Truncated maxp table (version %d)", version);
634
635     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
636     maxp->maxPoints = readU16(r);
637     maxp->maxContours = readU16(r);
638     maxp->maxComponentPoints = readU16(r);
639     maxp->maxComponentContours = readU16(r);
640     maxp->maxZones = readU16(r);
641     maxp->maxTwilightPoints = readU16(r);
642     maxp->maxStorage = readU16(r);
643     maxp->maxFunctionDefs = readU16(r);
644     maxp->maxInstructionDefs = readU16(r);
645     maxp->maxStackElements = readU16(r);
646     maxp->maxSizeOfInstructions = readU16(r);
647     maxp->maxComponentElements = readU16(r);
648     maxp->maxComponentDepth = readU16(r);
649     return maxp;
650 }
651 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
652 {
653     table_maxp_t*maxp = ttf->maxp;
654     if(!maxp) {
655         /* version 0.5 simplified maxp table */
656         writeU32(w, 0x00005000);
657         writeU16(w, ttf->num_glyphs);
658         return;
659     }
660     writeU32(w, 0x10000); //version
661     writeU16(w, ttf->num_glyphs);
662     writeU16(w, maxp->maxPoints);
663     writeU16(w, maxp->maxContours);
664     writeU16(w, maxp->maxComponentPoints);
665     writeU16(w, maxp->maxComponentContours);
666     writeU16(w, maxp->maxZones);
667     writeU16(w, maxp->maxTwilightPoints);
668     writeU16(w, maxp->maxStorage);
669     writeU16(w, maxp->maxFunctionDefs);
670     writeU16(w, maxp->maxInstructionDefs);
671     writeU16(w, maxp->maxStackElements);
672     writeU16(w, maxp->maxSizeOfInstructions);
673     writeU16(w, maxp->maxComponentElements);
674     writeU16(w, maxp->maxComponentDepth);
675 }
676 static void maxp_dump(ttf_t*ttf)
677 {
678     table_maxp_t*maxp = ttf->maxp;
679     if(!maxp) return;
680     printf("maxp->maxPoints: %d\n", maxp->maxPoints);
681     printf("maxp->maxContours: %d\n", maxp->maxContours);
682     printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
683     printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
684     printf("maxp->maxZones: %d\n", maxp->maxZones);
685     printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
686     printf("maxp->maxStorage: %d\n", maxp->maxStorage);
687     printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
688     printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
689     printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
690     printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
691     printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
692     printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
693 }
694 static void maxp_delete(ttf_t*ttf)
695 {
696     if(ttf->maxp)
697         free(ttf->maxp);
698     ttf->maxp=0;
699 }
700
701 static table_hea_t*hea_new(ttf_t*ttf)
702 {
703     table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
704     if(ttf->num_glyphs) {
705         int t;
706         for(t=0;t<ttf->num_glyphs;t++) {
707             if(ttf->glyphs[t].advance > hea->advanceWidthMax)
708                 hea->advanceWidthMax = ttf->glyphs[t].advance;
709             if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
710                 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
711             if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
712                 hea->minRightSideBearing = ttf->glyphs[t].xmax;
713             int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
714             if(width > hea->xMaxExtent)
715                 hea->xMaxExtent = width;
716         }
717         /* TODO: caret */
718     }
719     return hea;
720 }
721 static int hea_parse(memreader_t*r, ttf_t*ttf)
722 {
723     table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
724     U32 version = readU32(r);
725     ttf->ascent = readS16(r);
726     ttf->descent = readS16(r);
727     ttf->lineGap = readS16(r);
728     hea->advanceWidthMax = readU16(r);
729     hea->minLeftSideBearing = readS16(r);
730     hea->minRightSideBearing = readS16(r);
731     hea->xMaxExtent = readS16(r);
732     hea->caretSlopeRise = readS16(r);
733     hea->caretSlopeRun = readS16(r);
734     hea->caretOffset = readS16(r);
735     readS16(r); //reserved[0]
736     readS16(r); //reserved[1]
737     readS16(r); //reserved[2]
738     readS16(r); //reserved[3]
739     S16 metricDataFormat = readS16(r); //should be 0
740     if(metricDataFormat!=0) {
741         msg("<warning> Unknown metric format %d", metricDataFormat);
742     }
743     int num_advances = readU16(r);
744     if(num_advances > ttf->num_glyphs) {
745         msg("<warning> bad number of horizontal metrics: %d", num_advances);
746         num_advances = ttf->num_glyphs;
747     }
748     return num_advances;
749 }
750 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
751 {
752     table_hea_t*hea = ttf->hea;
753     writeU32(w, 0x00010000);
754     writeS16(w, ttf->ascent);
755     writeS16(w, ttf->descent);
756     writeS16(w, ttf->lineGap);
757     writeU16(w, hea->advanceWidthMax);
758     writeS16(w, hea->minLeftSideBearing);
759     writeS16(w, hea->minRightSideBearing);
760     writeS16(w, hea->xMaxExtent);
761     writeS16(w, hea->caretSlopeRise);
762     writeS16(w, hea->caretSlopeRun);
763     writeS16(w, hea->caretOffset);
764     writeS16(w, 0); //reserved
765     writeS16(w, 0); //reserved
766     writeS16(w, 0); //reserved
767     writeS16(w, 0); //reserved
768     writeS16(w, 0); //metricDataFormat
769     writeU16(w, num_advances);
770     return hea;
771 }
772 static void hea_dump(ttf_t*ttf)
773 {
774     table_hea_t*hea = ttf->hea;
775     if(!hea) return;
776     const char*dir = ttf->is_vertical?"v":"h";
777     printf("%shea->ascent: %d\n", dir, ttf->ascent);
778     printf("%shea->descent: %d\n", dir, ttf->descent);
779     printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
780     printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
781     printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
782     printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
783     printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
784     printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
785     printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
786     printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
787 }
788 static void hea_delete(ttf_t*ttf)
789 {
790     if(ttf->hea) {
791         free(ttf->hea);
792         ttf->hea=0;
793     }
794 }
795
796 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
797 {
798     U16 old_advance = 0;
799     int t;
800     if(num_advances > r->size/4)
801         num_advances = r->size/4;
802     for(t=0;t<num_advances;t++) {
803         old_advance = ttf->glyphs[t].advance = readU16(r);
804         ttf->glyphs[t].bearing = readS16(r);
805     }
806     int rest = (r->size - num_advances*4)/2;
807     if(ttf->num_glyphs < num_advances+rest) {
808         rest = ttf->num_glyphs-num_advances;
809     }
810     for(t=0;t<rest;t++) {
811         ttf->glyphs[t].advance = old_advance; 
812         ttf->glyphs[t].bearing = readS16(r);
813     }
814 }
815 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
816 {
817     int num_advances = ttf->num_glyphs;
818     if(ttf->num_glyphs>=2) {
819         int t;
820         for(t=ttf->num_glyphs-1;t>0;t--) {
821             if(ttf->glyphs[t-1].advance !=
822                ttf->glyphs[t].advance) break;
823         }
824         /* we need to store all individual advances as well
825            as one entry for the constant */
826         num_advances = t+1;
827     }
828
829     int t;
830     for(t=0;t<num_advances;t++) {
831         writeU16(w, ttf->glyphs[t].advance);
832         writeU16(w, ttf->glyphs[t].bearing);
833     }
834     for(;t<ttf->num_glyphs;t++) {
835         writeU16(w, ttf->glyphs[t].bearing);
836     }
837     return num_advances;
838 }
839
840 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
841 {
842     int t;
843     int num = ttf->num_glyphs+1;
844     U32*locations = rfx_calloc(num*sizeof(U32));
845     U32 lastloc = 0;
846     U32 loc = 0;
847     char warn_unsorted = 1;
848     if(size) {
849         if(num*4 > r->size) {
850             msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
851             num=r->size/4;
852         }
853         if(num*4 < r->size) {
854             msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
855         }
856         for(t=0;t<num;t++) {
857             locations[t] = loc = readU32(r);
858             if(lastloc > loc && warn_unsorted) {
859                 msg("<warning> Unsorted 'loca' table (32 bit)");
860                 warn_unsorted=0;
861             }
862             lastloc = loc;
863         }
864     } else {
865         if(num*2 > r->size) {
866             msg("<warning> Short 'loca' table (16 bit)");
867             num=r->size/2;
868         }
869         if(num*2 < r->size) {
870             msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
871         }
872         for(t=0;t<num;t++) {
873             locations[t] = loc = readU16(r)*2;
874             if(lastloc > loc && warn_unsorted) {
875                 msg("<warning> Unsorted 'loca' table");
876                 warn_unsorted=0;
877             }
878             lastloc = loc;
879         }
880     }
881     return locations;
882 }
883 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
884 {
885     int t;
886     char use_32bit = 0;
887     for(t=0;t<=ttf->num_glyphs;t++) {
888         if(locations[t]>=0x20000 || (locations[t]&1)) {
889             use_32bit = 1;
890             break;
891         }
892     }
893
894     if(use_32bit) {
895         for(t=0;t<=ttf->num_glyphs;t++) {
896             writeU32(w, locations[t]);
897         }
898         return 1;
899     } else {
900         for(t=0;t<=ttf->num_glyphs;t++) {
901             writeU16(w, locations[t]/2);
902         }
903         return 0;
904     }
905 }
906
907 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
908 {
909     ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
910
911     U16*endpoints = 0;
912     if(num_contours>0) {
913         endpoints = malloc(sizeof(U16)*num_contours);
914         int s;
915         int lastpos = -1;
916         for(s=0;s<num_contours;s++) {
917             int pos = endpoints[s] = readU16(r);
918             if(pos<=lastpos) {
919                 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
920             }
921             lastpos = pos;
922         }
923     }
924     U16 code_len = readU16(r);
925     if(code_len) {
926         glyph->code = malloc(sizeof(U16)*code_len);
927         readBlock(r, glyph->code, code_len);
928         glyph->code_size = code_len;
929     }
930
931     if(!endpoints) 
932         return 1;
933
934     /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", 
935             glyphnr, code_len, num_contours, glyph->num_points,
936             xmin, ymin, xmax, ymax);*/
937     INIT_READ(fx, r->mem, r->size, r->pos);
938     INIT_READ(fy, r->mem, r->size, r->pos);
939     
940     glyph->num_points = endpoints[num_contours-1] + 1;
941     glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
942
943     /* parse flag array (1st pass- to determine start of coordinates) */
944     int num=0;
945     while(num<glyph->num_points) {
946         U8 flag = readU8(r);
947         if(flag&0xc0) {
948             msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
949             free(glyph->points);
950             glyph->points = 0;
951             glyph->num_points = 0;
952             return 0;
953         }
954         int count = 1;
955         if(flag & 0x08) 
956             count += readU8(r);
957         if(count+num>glyph->num_points) {
958             msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
959             count = glyph->num_points-num;
960         }
961         num+=count;
962     }
963
964     /* parse flag array (2nd pass) and x coordinates */
965     num=0;
966     int x = 0;
967     char is_start=1;
968     int contour_pos=0;
969     int bytepos = r->pos;
970     while(num<glyph->num_points) {
971         U8 flag = readU8(&fx);
972         int count = flag&8?readU8(&fx)+1:1;
973         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
974         do {
975             char is_end=0;
976             if(contour_pos<num_contours && num==endpoints[contour_pos]) {
977                 contour_pos++;
978                 is_end=1;
979             }
980             int oldx = x;
981             if((flag&0x12) == 0x12) x += readU8(r);
982             else if((flag&0x12) == 0x02) x -= readU8(r);
983             else if((flag&0x12) == 0x00) x += readS16(r);
984             
985             glyph->points[num].x = x;
986             U8 f = flag&GLYPH_ON_CURVE;
987             if(is_start) f|=GLYPH_CONTOUR_START;
988             if(is_end) f|=GLYPH_CONTOUR_END;
989             glyph->points[num].flags = f;
990             num++;
991             is_start = is_end;
992         } while(--count);
993     }
994     
995     /* parse flag array (3rd pass) and y coordinates */
996     num=0;
997     int y = 0;
998     while(num<glyph->num_points) {
999         U8 flag = readU8(&fy);
1000         int count = flag&8?readU8(&fy)+1:1;
1001         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1002         do {
1003             if((flag&0x24) == 0x24) y += readU8(r);
1004             else if((flag&0x24) == 0x04) y -= readU8(r);
1005             else if((flag&0x24) == 0x00) y += readS16(r);
1006             glyph->points[num].y = y;
1007             num++;
1008         } while(--count);
1009     }
1010     free(endpoints);
1011     return 1;
1012 }
1013 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1014 {
1015     int t;
1016     char warn_about_compound_glyphs=0;
1017     for(t=0;t<ttf->num_glyphs;t++) {
1018         INIT_READ(r, rr->mem, rr->size, loca[t]);
1019         if(loca[t]==loca[t+1] || loca[t]==r.size)
1020             continue; //empty glyph
1021         if(r.pos+10>r.size) {
1022             msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", 
1023                     t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1024             break;
1025         }
1026         S16 num_contours = readS16(&r);
1027         ttf->glyphs[t].xmin = readS16(&r);
1028         ttf->glyphs[t].ymin = readS16(&r);
1029         ttf->glyphs[t].xmax = readS16(&r);
1030         ttf->glyphs[t].ymax = readS16(&r);
1031         
1032         if(num_contours<0) {
1033             if(warn_about_compound_glyphs)
1034                 msg("<error> Compound glyphs not supported yet");
1035             warn_about_compound_glyphs=0;
1036         } else {
1037             if(!parse_simple_glyph(ttf, &r, num_contours, t))
1038                 return;
1039         }
1040     }
1041
1042 }
1043 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1044 {
1045     /* endpoints array */
1046     int s;
1047     for(s=0;s<g->num_points;s++) {
1048         if(g->points[s].flags&GLYPH_CONTOUR_END)
1049             writeU16(w, s);
1050     }
1051     
1052     /* bytecode */
1053     writeU16(w, g->code_size);
1054     if(g->code_size)
1055         writeBlock(w, g->code, g->code_size);
1056
1057     /* flags */
1058     int lastx=0;
1059     int lasty=0;
1060     int lastflag=-1;
1061     int flagcount=0;
1062     for(s=0;s<g->num_points;s++) {
1063         ttfpoint_t*p = &g->points[s];
1064         int dx = p->x - lastx;
1065         int dy = p->y - lasty;
1066         U8 flags = p->flags&GLYPH_ON_CURVE;
1067         if(!dx) {
1068             flags|=0x10;
1069         } else if(dx<0 && dx>=-255) {
1070             flags|=0x02;
1071         } else if(dx>0 && dx<=255) {
1072             flags|=0x12;
1073         }
1074         if(!dy) {
1075             flags|=0x20;
1076         } else if(dy<0 && dy>=-255) {
1077             flags|=0x04;
1078         } else if(dy>0 && dy<=255) {
1079             flags|=0x24;
1080         }
1081         if(flags == lastflag && flagcount<255) {
1082             flagcount++;
1083         } else {
1084             if(lastflag>=0) {
1085                 if(flagcount) {
1086                     writeU8(w, lastflag|8);
1087                     writeU8(w, flagcount);
1088                 } else {
1089                     writeU8(w, lastflag);
1090                 }
1091             }
1092             lastflag = flags;
1093             flagcount = 0;
1094         }
1095         lastx = p->x;
1096         lasty = p->y;
1097     }
1098     if(lastflag>=0) {
1099         if(flagcount) {
1100             writeU8(w, lastflag|8);
1101             writeU8(w, flagcount);
1102         } else {
1103             writeU8(w, lastflag);
1104         }
1105     }
1106     /* coordinates */
1107     lastx=0;
1108     int bytepos = w->len;
1109     for(s=0;s<g->num_points;s++) {
1110         ttfpoint_t*p = &g->points[s];
1111         int dx = p->x - lastx;
1112         if(dx>32767 || dx<-32768) {
1113             msg("<error> Coordinate overflow in glyph");
1114         }
1115         lastx = p->x;
1116         if(dx>0 && dx<=255) writeU8(w, dx);
1117         else if(dx<0 && dx>=-255) writeU8(w, -dx);
1118         else if(dx) writeS16(w, dx);
1119     }
1120
1121     lasty=0;
1122     for(s=0;s<g->num_points;s++) {
1123         ttfpoint_t*p = &g->points[s];
1124         int dy = p->y - lasty;
1125         if(dy>32767 || dy<-32768) {
1126             msg("<error> Coordinate overflow in glyph");
1127         }
1128         lasty = p->y;
1129         if(dy>0 && dy<=255) writeU8(w, dy);
1130         else if(dy<0 && dy>=-255) writeU8(w, -dy);
1131         else if(dy) writeS16(w, dy);
1132     }
1133 }
1134 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1135 {
1136     U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1137     int t;
1138     for(t=0;t<ttf->num_glyphs;t++) {
1139         locations[t] = w->len;
1140         ttfglyph_t*g = &ttf->glyphs[t];
1141         int s;
1142         int num_contours = 0;
1143         for(s=0;s<g->num_points;s++) {
1144             if(g->points[s].flags&GLYPH_CONTOUR_END)
1145                 num_contours++;
1146         }
1147         writeS16(w, num_contours?num_contours:1);
1148         writeS16(w, g->xmin);
1149         writeS16(w, g->ymin);
1150         writeS16(w, g->xmax);
1151         writeS16(w, g->ymax);
1152         
1153         if(!num_contours) {
1154             /* some ttf parsers can't deal with zero contours, so in the case
1155                of an empty glyph, write a single point (0,0) */
1156             writeU16(w, 0); //endpoint of 1st contour
1157             writeU16(w, g->code_size);
1158             if(g->code_size)
1159                 writeBlock(w, g->code, g->code_size);
1160             writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1161         } else {
1162             write_simple_glyph(w, g);
1163         }
1164     }
1165     locations[t] = w->len;
1166     return locations;
1167 }
1168 void glyf_dump(ttf_t* ttf)
1169 {
1170     if(!ttf->glyphs) return;
1171     int t;
1172     for(t=0;t<ttf->num_glyphs;t++) {
1173         ttfglyph_t*g = &ttf->glyphs[t];
1174         printf("glyph %d)\n", t);
1175         printf("  advance=%d\n", g->advance);
1176         printf("  bearing=%d\n", g->bearing);
1177         printf("  bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1178         printf("  points=(");
1179         int s;
1180         for(s=0;s<g->num_points;s++) {
1181             if(s) printf(",");
1182             printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1183         }
1184         printf(")\n");
1185         if(g->code_size) 
1186             hexdump(g->code, g->code_size, "  ");
1187     }
1188 }
1189 void glyf_delete(ttf_t* ttf)
1190 {
1191     if(!ttf->glyphs) 
1192         return;
1193     int t;
1194     for(t=0;t<ttf->num_glyphs;t++) {
1195         if(ttf->glyphs[t].code) {
1196             free(ttf->glyphs[t].code);
1197             ttf->glyphs[t].code = 0;
1198         }
1199         if(ttf->glyphs[t].points) {
1200             free(ttf->glyphs[t].points);
1201             ttf->glyphs[t].points = 0;
1202         }
1203     }
1204     free(ttf->glyphs);ttf->glyphs=0;
1205 }
1206
1207 static void grow_unicode(ttf_t*ttf, int index)
1208 {
1209     int size = index+1;
1210     if(!ttf->unicode) {
1211         ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1212     } else if(ttf->unicode_size<size) {
1213         ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1214         memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1215     }
1216     ttf->unicode_size = size;
1217 }
1218 void cmap_parse(memreader_t*r, ttf_t*ttf)
1219 {
1220     readU16(r); // version (0)
1221     int num_subtables = readU16(r);
1222     int t;
1223     if(r->pos+num_subtables*8 > r->size) {
1224         msg("<warning> CMap overflow");
1225         num_subtables = (r->size-r->pos)/8;
1226     }
1227     unicode_t*data = 0;
1228     for(t=0;t<num_subtables;t++) {
1229         U16 platform = readU16(r);
1230         U16 encoding = readU16(r);
1231         U32 offset = readU32(r);
1232         if(offset>r->size) {
1233             msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1234             continue;
1235         }
1236
1237         int is_unicode = platform==0 ||
1238                          platform==3 && encoding == 1 ||
1239                          platform==3 && encoding == 10;
1240
1241         if(!is_unicode) 
1242             continue;
1243
1244         INIT_READ(t, r->mem, r->size, offset);
1245         U16 format = readU16(&t);
1246         int length = readU16(&t);
1247         U16 language = readU16(&t);
1248
1249         if(language)
1250             msg("<warning> Language code %02x in unicode mapping", language);
1251
1252         int num = 0;
1253         if(format == 0) {
1254             num = length-6;
1255             if(t.pos+length > t.size) {
1256                 msg("<warning> overflow in format 0 cmap table");
1257                 num = t.size-t.pos;
1258             }
1259             data = malloc(num*sizeof(unicode_t));
1260             int s;
1261             grow_unicode(ttf, num);
1262             for(s=0;s<num;s++) {
1263                 ttf->unicode[s] = readU8(&t);
1264             }
1265         } else if(format == 4) {
1266             U16 segment_count = readU16(&t); 
1267             if(segment_count&1) {
1268                 msg("<error> Bad segmentx2 count %d", segment_count);
1269                 continue;
1270             }
1271             segment_count>>=1;
1272             readU16(&t); //searchrange
1273             readU16(&t); //entry selector
1274             readU16(&t); //range shift
1275             INIT_READ(r_end, t.mem, t.size, t.pos);
1276             INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1277             INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1278             INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1279             int glyphmap_start = t.pos+2+segment_count*8;
1280             int s;
1281             for(s=0;s<segment_count;s++) {
1282                 U16 start = readU16(&r_start);
1283                 U16 end = readU16(&r_end);
1284                 U16 delta = readU16(&r_delta);
1285                 U16 range = readU16(&r_range);
1286                 if(start==0xffff && end==0xffff && delta==1) {
1287                     /* this is a common (maybe even required) occurence in fonts 
1288                        which explicitly map "unicode undefined" (0xffff) to 
1289                        "glyph undefined" (0).
1290                        We don't want to blow our unicode table up to 65536 just
1291                        because of this, so ignore this entry.
1292                      */
1293                     continue;
1294                 }
1295                 grow_unicode(ttf, end);
1296                 int u;
1297                 if(!range) {
1298                     for(u=start;u<=end;u++) {
1299                         ttf->unicode[u] = (u + delta) & 0xffff;
1300                     }
1301                 } else {
1302                     INIT_READ(g, t.mem, t.size, r_range.pos-2+range);
1303                     for(u=start;u<=end;u++) {
1304                         ttf->unicode[u] = readU16(&g);
1305                     }
1306                 }
1307             }
1308         }
1309     }
1310 }
1311 static int segment_size(unicode_t*unicode, int pos, int size)
1312 {
1313     int s;
1314     int count=0;
1315     for(s=pos;s<size;s++) {
1316         if(!unicode[s])
1317             count++;
1318         if(count>4) {
1319             /* a segment costs us 8 bytes, so for more than 4 consecutive 
1320                zero entries (16 bit each) in the glyph index array,
1321                it pays off to start a new segment */
1322             break;
1323         }
1324     }
1325     s -= count; // go to the last filled in entry
1326     if(s==size)
1327         return size-1;
1328     return s;
1329 }
1330 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1331 {
1332     writeU16(w, 0);  //version
1333     writeU16(w, 2);  //two tables
1334
1335     writeU16(w, 0);  //platform (unicode)
1336     writeU16(w, 3);  //encoding (unicode 2.0)
1337     writeU32(w, 20); //offset
1338
1339     writeU16(w, 3);  //platform (windows)
1340     writeU16(w, 1);  //encoding (unicode basic multilingual plane UCS-2)
1341     writeU32(w, 20); //offset
1342
1343     writeU16(w, 4); // format=4
1344     int length_pos = w->len;
1345     writeU16(w, 0); // length: we don't know yet
1346     writeU16(w, 0); // language (n/a for unicode)
1347     int num_segments_pos = w->len;
1348     writeU16(w, 0); //number of segments: we don't know yet either
1349     writeU16(w, 0); //searchrange
1350     writeU16(w, 0); //entry selector
1351     writeU16(w, 0); //range shift
1352
1353     int pos=0;
1354     int num_segments=0;
1355     while(pos < ttf->unicode_size) {
1356         if(!ttf->unicode[pos]) {
1357             pos++;
1358             continue;
1359         }
1360         int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1361         pos = s+1;
1362         num_segments++;
1363     }
1364
1365     num_segments++; // account for 0xffff mapping
1366
1367     int t;
1368     int end_pos = w->len;
1369     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1370     writeU16(w, 0); //reserved byte
1371     int start_pos = w->len;
1372     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1373     int delta_pos = w->len;
1374     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1375     int range_pos = w->len;
1376     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1377     
1378     w->data[num_segments_pos]=(num_segments*2)>>8;
1379     w->data[num_segments_pos+1]=(num_segments*2);
1380
1381     pos=0;
1382     num_segments = 0;
1383     while(pos < ttf->unicode_size) {
1384         if(!ttf->unicode[pos]) {
1385             pos++;
1386             continue;
1387         }
1388         U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1389         w->data[end_pos++]=end>>8;
1390         w->data[end_pos++]=end;
1391         w->data[start_pos++]=pos>>8;
1392         w->data[start_pos++]=pos;
1393         int s;
1394         U16 delta = ttf->unicode[pos]-pos;
1395         char do_delta=1;
1396         for(s=pos+1;s<=end;s++) {
1397             U16 delta2 = ttf->unicode[pos]-pos;
1398             if(delta2!=delta) {
1399                 do_delta=0;
1400                 break;
1401             }
1402         }
1403         U16 range;
1404         if(do_delta) {
1405             range = 0;
1406         } else {
1407             delta = 0;
1408             range = w->len - range_pos+num_segments*2;
1409             for(s=pos;s<=end;s++) {
1410                 writeU16(w, ttf->unicode[s]);
1411             }
1412         }
1413         w->data[delta_pos++]=delta>>8;
1414         w->data[delta_pos++]=delta;
1415         w->data[range_pos++]=range>>8;
1416         w->data[range_pos++]=range;
1417         num_segments++;
1418         pos = end+1;
1419     }
1420
1421     /* write out a mapping from 0xffff to 0- seems to be required
1422        by some libraries (e.g. fonttools) */
1423     w->data[end_pos++]=0xff;
1424     w->data[end_pos++]=0xff;
1425     w->data[start_pos++]=0xff;
1426     w->data[start_pos++]=0xff;
1427     w->data[delta_pos++]=0;
1428     w->data[delta_pos++]=1;
1429     w->data[range_pos++]=0;
1430     w->data[range_pos++]=0;
1431
1432     w->data[length_pos]=(w->len-20)>>8;
1433     w->data[length_pos+1]=w->len-20;
1434 }
1435 void cmap_delete(ttf_t*ttf)
1436 {
1437     if(ttf->unicode) {
1438         free(ttf->unicode);
1439         ttf->unicode=0;
1440     }
1441     ttf->unicode_size=0;
1442 }
1443 void name_parse(memreader_t*r, ttf_t*ttf)
1444 {
1445     U16 format = readU16(r);
1446     U16 count = readU16(r);
1447     U16 offset = readU16(r);
1448    
1449     int t;
1450     for(t=0;t<count;t++) {
1451         U16 platform = readU16(r);
1452         U16 encoding = readU16(r);
1453         U16 language = readU16(r);
1454         U16 name_id = readU16(r);
1455         U16 len = readU16(r);
1456         U16 offset_2 = readU16(r);
1457         if(name_id==4) {
1458             if(ttf->name)
1459                 free(ttf->name);
1460             ttf->name = strdup_n(&r->mem[offset+offset_2], len);
1461         }
1462     }
1463 }
1464 void name_write(ttf_t*ttf, ttf_table_t*table)
1465 {
1466     writeU16(table, 0); //format
1467     writeU16(table, 1); //count
1468     int offset = 18;
1469     writeU16(table, offset); //offset
1470
1471     writeU16(table, 1); //platform id
1472     writeU16(table, 0); //encoding id
1473     writeU16(table, 0); //language
1474     writeU16(table, 4); //4: full name
1475     int len = strlen(ttf->name);
1476     writeU16(table, len);
1477     writeU16(table, table->len+2 - offset);
1478     int t;
1479     for(t=0;t<len;t++) {
1480         writeU8(table, ttf->name[t]);
1481     }
1482 }
1483 void name_delete(ttf_t*ttf)
1484 {
1485     if(ttf->name)
1486         free(ttf->name);
1487 }
1488
1489 static table_post_t*post_new(ttf_t*ttf)
1490 {
1491     table_post_t*post = rfx_calloc(sizeof(table_post_t));
1492     return post;
1493 }
1494 void post_parse(memreader_t*r, ttf_t*ttf)
1495 {
1496     table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1497     U16 format = readU16(r);
1498     post->italic_angle = readU16(r);
1499     post->underline_position = readU16(r);
1500     post->underline_thickness = readU16(r);
1501     U16 is_monospaced = readU16(r);
1502     readU16(r); // min mem 42
1503     readU16(r);
1504     readU16(r); // min mem 1
1505     readU16(r);
1506 }
1507 void post_write(ttf_t*ttf, ttf_table_t*table)
1508 {
1509     table_post_t*post = ttf->post;
1510     writeU32(table, 0x00030000);
1511     writeU32(table, post->italic_angle);
1512     writeU16(table, post->underline_position);
1513     writeU16(table, post->underline_thickness);
1514     writeU32(table, 0); //is monospaced TODO
1515     writeU32(table, 0); //min mem 42
1516     writeU32(table, 0);
1517     writeU32(table, 0); //min mem 1
1518     writeU32(table, 0);
1519 }
1520 void post_delete(ttf_t*ttf)
1521 {
1522     if(ttf->post)
1523         free(ttf->post);
1524 }
1525
1526 static int ttf_parse_tables(ttf_t*ttf)
1527 {
1528     ttf_table_t*table;
1529
1530     table = ttf_find_table(ttf, TAG_HEAD);
1531     if(!table) {
1532         msg("<error> Font has no head table");
1533         return 0;
1534     }
1535     INIT_READ(m, table->data, table->len, 0);
1536     int loc_index = head_parse(ttf, &m);
1537     ttf_table_delete(ttf, table);
1538     
1539     table = ttf_find_table(ttf, TAG_MAXP);
1540     if(!table) {
1541         msg("<error> Font has no maxp table");
1542         return 0;
1543     }
1544     INIT_READ(m2, table->data, table->len, 0);
1545     ttf->maxp = maxp_parse(ttf, &m2);
1546     ttf_table_delete(ttf, table);
1547     
1548     if(!ttf->num_glyphs) {
1549         msg("<error> Invalid number of characters");
1550         return 0;
1551     }
1552     ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1553
1554     table = ttf_find_table(ttf, TAG_OS2);
1555     if(table) {
1556         INIT_READ(m, table->data, table->len, 0);
1557         ttf->os2 = os2_parse(&m);
1558         ttf_table_delete(ttf, table);
1559     }
1560
1561     table = ttf_find_table(ttf, TAG_HHEA);
1562     if(table) {
1563         INIT_READ(m, table->data, table->len, 0);
1564         int num_advances = hea_parse(&m, ttf);
1565         ttf_table_delete(ttf, table);
1566         
1567         table = ttf_find_table(ttf, TAG_HMTX);
1568         if(table) {
1569             INIT_READ(m, table->data, table->len, 0);
1570             mtx_parse(&m, ttf, num_advances);
1571             ttf_table_delete(ttf, table);
1572         }
1573     } else {
1574         table = ttf_find_table(ttf, TAG_VHEA);
1575         if(table) {
1576             ttf->is_vertical=1;
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_VMTX);
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             msg("<error> Font contains neither HHEA nor VHEA");
1589         }
1590     }
1591     table = ttf_find_table(ttf, TAG_LOCA);
1592     if(table) {
1593         INIT_READ(m, table->data, table->len, 0);
1594         U32*loca = loca_parse(&m, ttf, loc_index);
1595         ttf_table_delete(ttf, table);
1596         table = ttf_find_table(ttf, TAG_GLYF);
1597         if(table) {
1598             INIT_READ(m, table->data, table->len, 0);
1599             glyf_parse(&m, ttf, loca);
1600             ttf_table_delete(ttf, table);
1601         }
1602         free(loca);
1603     }
1604     
1605     table = ttf_find_table(ttf, TAG_CMAP);
1606     if(table) {
1607         INIT_READ(m, table->data, table->len, 0);
1608         cmap_parse(&m, ttf);
1609         ttf_table_delete(ttf, table);
1610     }
1611     
1612     table = ttf_find_table(ttf, TAG_NAME);
1613     if(table) {
1614         INIT_READ(m, table->data, table->len, 0);
1615         name_parse(&m, ttf);
1616         ttf_table_delete(ttf, table);
1617     }
1618
1619     table = ttf_find_table(ttf, TAG_POST);
1620     if(table) {
1621         INIT_READ(m, table->data, table->len, 0);
1622         post_parse(&m, ttf);
1623         ttf_table_delete(ttf, table);
1624     }
1625
1626     return 1;
1627 }
1628 static void ttf_collapse_tables(ttf_t*ttf)
1629 {
1630     ttf_table_t*table;
1631    
1632     table = ttf_addtable(ttf, TAG_MAXP);
1633     maxp_write(ttf, table);
1634     maxp_delete(ttf);
1635
1636     table = ttf_addtable(ttf, TAG_OS2);
1637     os2_write(ttf, table);
1638     os2_delete(ttf);
1639
1640     if(!ttf->is_vertical) {
1641         table = ttf_addtable(ttf, TAG_HMTX);
1642         int num_advances = mtx_write(ttf, table);
1643         table = ttf_addtable(ttf, TAG_HHEA);
1644         hea_write(ttf, table, num_advances);
1645     } else {
1646         table = ttf_addtable(ttf, TAG_VMTX);
1647         int num_advances = mtx_write(ttf, table);
1648         table = ttf_addtable(ttf, TAG_VHEA);
1649         hea_write(ttf, table, num_advances);
1650     }
1651         
1652     int loca_size=0;
1653     if(ttf->num_glyphs) {
1654         table = ttf_addtable(ttf, TAG_CMAP);
1655         cmap_write(ttf, table);
1656         cmap_delete(ttf);
1657
1658         table = ttf_addtable(ttf, TAG_GLYF);
1659         U32*locations = glyf_write(ttf, table);
1660         glyf_delete(ttf);
1661         
1662         table = ttf_addtable(ttf, TAG_LOCA);
1663         loca_size = loca_write(ttf, table, locations);
1664         free(locations);
1665     }
1666
1667     if(ttf->name) {
1668         table = ttf_addtable(ttf, TAG_NAME);
1669         name_write(ttf, table);
1670         name_delete(ttf);
1671     }
1672     if(ttf->post) {
1673         table = ttf_addtable(ttf, TAG_POST);
1674         post_write(ttf, table);
1675         post_delete(ttf);
1676     }
1677     
1678     table = ttf_addtable(ttf, TAG_HEAD);
1679     head_write(ttf, table, loca_size);
1680     head_delete(ttf);
1681 }
1682
1683 ttf_t*ttf_new()
1684 {
1685     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1686     ttf->version = VERSION_1_0;
1687     return ttf;
1688 }
1689 ttf_t* ttf_load(void*data, int length)
1690 {
1691     INIT_READ(r,data,length, 0);
1692
1693     if(length<12) {
1694         msg("<error> Truncated Truetype file (%d bytes)", length);
1695         return 0;
1696     }
1697
1698     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1699     ttf->version = readU32(&r);
1700     if(ttf->version == TTCFTAG) {
1701         /* a ttc collection is a number of truetype fonts
1702            packaged together */
1703         if(length<16) {
1704             msg("<error> Truncated TTC file (%d bytes)", length);
1705             return 0;
1706         }
1707         U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1708         U32 num_fonts = readU32(&r); // number of fonts
1709         U32 font1_position = readU32(&r);
1710         if(font1_position+12 > length) {\
1711             msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1712             return 0;
1713         }
1714         r.pos = font1_position;
1715         ttf->version = readU32(&r);
1716     }
1717     
1718     int num_tables = readU16(&r);
1719     
1720     readU16(&r); //search range
1721     readU16(&r); //entry selector
1722     readU16(&r); //range shift
1723
1724     if(num_tables*16 > length) {
1725         msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1726         if(ttf->version != OPENTYPE && 
1727            ttf->version != TRUETYPE_MACOS && 
1728            ttf->version != VERSION_1_0) {
1729             // bad table length, weird version. This is probably not a ttf file.
1730             return 0;
1731         }
1732     }
1733
1734     U32*table_data = malloc(16*num_tables);
1735     int t;
1736     for(t=0;t<num_tables*4;t++) {
1737         table_data[t] = readU32(&r);
1738     }
1739     for(t=0;t<num_tables;t++) {
1740         U32 tag = table_data[t*4];
1741         U32 checksum = table_data[t*4+1];
1742         U32 pos = table_data[t*4+2];
1743         U32 len = table_data[t*4+3];
1744
1745         if(pos+len > length) {
1746             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);
1747         } else {
1748             U8*mem = malloc(len);
1749             r.pos = pos;
1750             readBlock(&r, mem, len);
1751             
1752             ttf_table_t*table = ttf_addtable(ttf, tag);
1753             table->data = mem;
1754             table->len = table->memsize = len;
1755 #if 0
1756             U32 checksum2 = ttf_table_checksum(table);
1757             if(checksum2!=checksum) {
1758                 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
1759                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1760                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1761                         len, checksum2, checksum);
1762             }
1763 #endif
1764         }
1765     }
1766     free(table_data);
1767
1768     if(!ttf_parse_tables(ttf)) 
1769         return 0;
1770
1771     return ttf;
1772 }
1773 void ttf_create_truetype_tables(ttf_t*ttf)
1774 {
1775     if(!ttf->head) 
1776         ttf->head = head_new(ttf);
1777     if(!ttf->maxp) 
1778         ttf->maxp = maxp_new(ttf);
1779     if(!ttf->hea)
1780         ttf->hea = hea_new(ttf);
1781     if(!ttf->os2)
1782         ttf->os2 = os2_new(ttf);
1783     if(!ttf->post)
1784         ttf->post = post_new(ttf);
1785 }
1786 ttf_table_t* ttf_write(ttf_t*ttf)
1787 {
1788     ttf_collapse_tables(ttf);
1789    
1790     ttf_table_t*file = ttf_table_new(0);
1791     writeU32(file, VERSION_1_0);
1792
1793     /* write number of tables */
1794     int num_tables=0;
1795     ttf_table_t*t = ttf->tables;
1796     while(t) {
1797         num_tables++;
1798         t = t->next;
1799     }
1800     writeU16(file, num_tables);
1801     
1802     /* write search range */
1803     int tmp = num_tables;
1804     int search_range = 0;
1805     while(tmp) {
1806         search_range = tmp;
1807         tmp = tmp&(tmp-1);
1808     }
1809     tmp = search_range;
1810     search_range*=16;
1811     writeU16(file, search_range);
1812
1813     /* write entry selector */
1814     int entry_selector = 0;
1815     while(tmp>1) {
1816         tmp>>=1;
1817         entry_selector++;
1818     }
1819     writeU16(file, entry_selector);
1820
1821     /* write range shift */
1822     int range_shift = num_tables*16 - search_range;
1823     writeU16(file, range_shift);
1824
1825     /* write table dictionary */
1826     int table_dictionary_pos = file->len;
1827     int data_pos = file->len + num_tables*16;
1828     for(t=ttf->tables;t;t=t->next) {
1829         writeU32(file, t->id);
1830         writeU32(file, ttf_table_checksum(t));
1831         writeU32(file, data_pos);
1832         writeU32(file, t->len);
1833         data_pos += t->len;
1834         data_pos += (-t->len)&3; //pad
1835     }
1836
1837     /* write tables */
1838     int head_pos = 0;
1839     U8 zero[4]={0,0,0,0};
1840     for(t=ttf->tables;t;t=t->next) {
1841         if(t->id == TAG_HEAD)
1842             head_pos = file->len;
1843         writeBlock(file, t->data, t->len);
1844         writeBlock(file, zero, (-t->len)&3); //pad
1845     }
1846     U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1847     U8*checksum2 = file->data + head_pos + 8;
1848     checksum2[0] = checksum>>24;
1849     checksum2[1] = checksum>>16;
1850     checksum2[2] = checksum>>8;
1851     checksum2[3] = checksum>>0;
1852     return file;
1853 }
1854 void ttf_save(ttf_t*ttf, const char*filename)
1855 {
1856     ttf_table_t* t = ttf_write(ttf);
1857     FILE*fi = fopen(filename, "wb");
1858     if(!fi) {
1859         perror(filename);
1860         return;
1861     }
1862     fwrite(t->data, t->len, 1, fi);
1863     fclose(fi);
1864     ttf_table_delete(0, t);
1865 }
1866 void ttf_dump(ttf_t*ttf)
1867 {
1868     msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1869     ttf_table_t*table = ttf->tables;
1870     while(table) {
1871         U32 tag = table->id;
1872         msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", 
1873                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, 
1874                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1875         table = table->next;
1876     }
1877     //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1878
1879     head_dump(ttf);
1880     hea_dump(ttf);
1881     os2_dump(ttf);
1882     maxp_dump(ttf);
1883     glyf_dump(ttf);
1884 }
1885 void ttf_destroy_tables(ttf_t*ttf)
1886 {
1887     ttf_table_t*table = ttf->tables;
1888     while(table) {
1889         ttf_table_t*next = table->next;
1890         free(table->data);
1891         free(table);
1892         table = next;
1893     }
1894     ttf->tables = 0;
1895 }
1896 void ttf_reduce(ttf_t*ttf)
1897 {
1898     ttf_destroy_tables(ttf);
1899 }
1900 void ttf_destroy(ttf_t*ttf)
1901 {
1902     ttf_destroy_tables(ttf);
1903     maxp_delete(ttf);
1904     os2_delete(ttf);
1905     head_delete(ttf);
1906     hea_delete(ttf);
1907     glyf_delete(ttf);
1908     post_delete(ttf);
1909     free(ttf);
1910 }
1911
1912 #ifdef MAIN
1913 int main(int argn, const char*argv[])
1914 {
1915     setConsoleLogging(7);
1916     const char*filename = "comic.ttf";
1917     if(argn>1) 
1918         filename = argv[1];
1919     //msg("<notice> Loading %s", filename);
1920     memfile_t*m = memfile_open(filename);
1921     ttf_t*ttf = ttf_load(m->data, m->len);
1922     ttf_reduce(ttf);
1923     ttf->name = strdup("testfont");
1924     if(!ttf) return 1;
1925     memfile_close(m);
1926     //ttf_dump(ttf);
1927     //printf("os2 version: %04x (%d), maxp size: %d\n", 
1928 //          ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1929     ttf_save(ttf, "testfont.ttf");
1930     ttf_destroy(ttf);
1931     return 0;
1932
1933 }
1934 #endif