added truetype parser
[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 "bitio.h"
26 #include "log.h"
27 #include "os.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 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 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 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 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_os2_t*os2_parse(memreader_t*r)
262 {
263     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
264     U16 version = readU16(r);
265     if(version!=0 && version!=1 && version!=2)
266         msg("<warning> Unknown OS2 version: %04x", version);
267     os2->xAvgCharWidth = readS16(r);
268     os2->usWeightClass = readU16(r);
269     os2->usWidthClass = readU16(r);
270     os2->fsType = readU16(r);
271     os2->ySubscriptXSize = readU16(r);
272     os2->ySubscriptYSize = readU16(r);
273     os2->ySubscriptXOffset = readU16(r);
274     os2->ySubscriptYOffset = readU16(r);
275     os2->ySuperscriptXSize = readU16(r);
276     os2->ySuperscriptYSize = readU16(r);
277     os2->ySuperscriptXOffset = readU16(r);
278     os2->ySuperscriptYOffset = readU16(r);
279     os2->yStrikeoutSize = readU16(r);
280     os2->yStrikeoutPosition = readU16(r);
281     os2->sFamilyClass = readU16(r);
282     os2->panose_FamilyType = readU8(r);
283     os2->panose_SerifStyle = readU8(r);
284     os2->panose_Weight = readU8(r);
285     os2->panose_Proportion = readU8(r);
286     os2->panose_Contrast = readU8(r);
287     os2->panose_StrokeVariation = readU8(r);
288     os2->panose_ArmStyle = readU8(r);
289     os2->panose_Letterform = readU8(r);
290     os2->panose_Midline = readU8(r);
291     os2->panose_XHeight = readU8(r);
292     os2->ulCharRange[0] = readU32(r);
293     os2->ulCharRange[1] = readU32(r);
294     os2->ulCharRange[2] = readU32(r);
295     os2->ulCharRange[3] = readU32(r);
296     os2->achVendID[0] = readU8(r);
297     os2->achVendID[1] = readU8(r);
298     os2->achVendID[2] = readU8(r);
299     os2->achVendID[3] = readU8(r);
300     os2->fsSelection = readU16(r);
301     os2->fsFirstCharIndex = readU16(r);
302     os2->fsLastCharIndex = readU16(r);
303     os2->sTypoAscender = readS16(r);
304     os2->sTypoDescender = readS16(r);
305     os2->sTypoLineGap = readS16(r);
306     os2->usWinAscent = readU16(r);
307     os2->usWinDescent = readU16(r);
308     if(version<1) return os2;
309     os2->ulCodePageRange1 = readU32(r);
310     os2->ulCodePageRange2 = readU32(r);
311     if(version<2) return os2;
312     os2->sxHeight = readS16(r);
313     os2->sCapHeight = readS16(r);
314     os2->usDefaultChar = readU16(r);
315     os2->usBreakChar = readU16(r);
316     os2->usMaxContext = readU16(r);
317     return os2;
318 }
319
320 static os2_write(ttf_t*ttf, ttf_table_t*w)
321 {
322     table_os2_t*os2 = ttf->os2;
323     U16 version=1;
324     if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
325         version=2;
326     }
327     writeU16(w, version);
328     writeS16(w, os2->xAvgCharWidth);
329     writeU16(w, os2->usWeightClass);
330     writeU16(w, os2->usWidthClass);
331     writeU16(w, os2->fsType);
332     writeU16(w, os2->ySubscriptXSize);
333     writeU16(w, os2->ySubscriptYSize);
334     writeU16(w, os2->ySubscriptXOffset);
335     writeU16(w, os2->ySubscriptYOffset);
336     writeU16(w, os2->ySuperscriptXSize);
337     writeU16(w, os2->ySuperscriptYSize);
338     writeU16(w, os2->ySuperscriptXOffset);
339     writeU16(w, os2->ySuperscriptYOffset);
340     writeU16(w, os2->yStrikeoutSize);
341     writeU16(w, os2->yStrikeoutPosition);
342     writeU16(w, os2->sFamilyClass);
343     writeU8(w, os2->panose_FamilyType);
344     writeU8(w, os2->panose_SerifStyle);
345     writeU8(w, os2->panose_Weight);
346     writeU8(w, os2->panose_Proportion);
347     writeU8(w, os2->panose_Contrast);
348     writeU8(w, os2->panose_StrokeVariation);
349     writeU8(w, os2->panose_ArmStyle);
350     writeU8(w, os2->panose_Letterform);
351     writeU8(w, os2->panose_Midline);
352     writeU8(w, os2->panose_XHeight);
353     writeU32(w, os2->ulCharRange[0]);
354     writeU32(w, os2->ulCharRange[1]);
355     writeU32(w, os2->ulCharRange[2]);
356     writeU32(w, os2->ulCharRange[3]);
357     writeU8(w, os2->achVendID[0]);
358     writeU8(w, os2->achVendID[1]);
359     writeU8(w, os2->achVendID[2]);
360     writeU8(w, os2->achVendID[3]);
361     writeU16(w, os2->fsSelection);
362     writeU16(w, os2->fsFirstCharIndex);
363     writeU16(w, os2->fsLastCharIndex);
364     writeS16(w, os2->sTypoAscender);
365     writeS16(w, os2->sTypoDescender);
366     writeS16(w, os2->sTypoLineGap);
367     writeU16(w, os2->usWinAscent);
368     writeU16(w, os2->usWinDescent);
369     if(version<1) return;
370     writeU32(w, os2->ulCodePageRange1);
371     writeU32(w, os2->ulCodePageRange2);
372     if(version<2) return;
373     writeS16(w, os2->sxHeight);
374     writeS16(w, os2->sCapHeight);
375     writeU16(w, os2->usDefaultChar);
376     writeU16(w, os2->usBreakChar);
377     writeU16(w, os2->usMaxContext);
378 }
379 static void os2_delete(ttf_t*ttf)
380 {
381     if(ttf->os2)
382         free(ttf->os2);
383     ttf->os2=0;
384 }
385
386 static os2_dump(ttf_t*ttf)
387 {
388     table_os2_t*os2 = ttf->os2;
389     if(!os2) return;
390     printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
391     printf("os2->usWeightClass: %d\n", os2->usWeightClass);
392     printf("os2->usWidthClass: %d\n", os2->usWidthClass);
393     printf("os2->fsType: %d\n", os2->fsType);
394     printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
395     printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
396     printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
397     printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
398     printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
399     printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
400     printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
401     printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
402     printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
403     printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
404     printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
405     printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
406     printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
407     printf("os2->panose_Weight: %d\n", os2->panose_Weight);
408     printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
409     printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
410     printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
411     printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
412     printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
413     printf("os2->panose_Midline: %d\n", os2->panose_Midline);
414     printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
415     printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
416     printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
417     printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
418     printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
419     printf("os2->achVendID[0]: %d\n", os2->achVendID[0]);
420     printf("os2->achVendID[1]: %d\n", os2->achVendID[1]);
421     printf("os2->achVendID[2]: %d\n", os2->achVendID[2]);
422     printf("os2->achVendID[3]: %d\n", os2->achVendID[3]);
423     printf("os2->fsSelection: %d\n", os2->fsSelection);
424     printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
425     printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
426     printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
427     printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
428     printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
429     printf("os2->usWinAscent: %d\n", os2->usWinAscent);
430     printf("os2->usWinDescent: %d\n", os2->usWinDescent);
431     printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
432     printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
433     printf("os2->sxHeight: %d\n", os2->sxHeight);
434     printf("os2->sCapHeight: %d\n", os2->sCapHeight);
435     printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
436     printf("os2->usBreakChar: %d\n", os2->usBreakChar);
437     printf("os2->usMaxContext: %d\n", os2->usMaxContext);
438 }
439
440 static int head_parse(ttf_t*ttf, memreader_t*r)
441 {
442     ttf->head = rfx_calloc(sizeof(table_head_t));
443     U32 version = readU32(r);
444     if(version!=VERSION_1_0) 
445         msg("<warning> Font HEAD has unknown version %08x", version);
446     U32 revision = readU32(r);
447     if(revision!=VERSION_1_0) 
448         msg("<warning> Font HEAD has unknown revision %08x", revision);
449     U32 checksum2 = readU32(r);
450     U32 magic = readU32(r);
451     if(magic!=0x5f0f3cf5) 
452         msg("<warning> Font HEAD has unknown magic number %08x", magic);
453     ttf->head->flags = readU16(r);
454     ttf->head->units_per_em = readU16(r);
455     readU32(r);readU32(r); //created
456     readU32(r);readU32(r); //modified
457     ttf->head->xmin = readU16(r);
458     ttf->head->ymin = readU16(r);
459     ttf->head->xmax = readU16(r);
460     ttf->head->ymax = readU16(r);
461     ttf->head->macStyle = readU16(r);
462     ttf->head->lowest_readable_size = readU16(r); //in pixels
463     ttf->head->dir_hint = readS16(r);
464     int loc_index = readS16(r); //used in 'loca' table
465     if(loc_index>1)
466         msg("<warning> loca index format %d unknown", loc_index);
467     U16 glyph_data_format = readS16(r);
468     if(glyph_data_format!=0)
469         msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
470     return loc_index;
471 }
472
473 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
474 {
475     writeU32(w, 0x10000);
476     writeU32(w, 0x10000);
477     writeU32(w, 0); //checksum
478     writeU32(w, 0x5f0f3cf5); //magic
479     writeU16(w, ttf->head->flags);
480     writeU16(w, ttf->head->units_per_em);
481     writeU32(w, 0);writeU32(w, 0); //created
482     writeU32(w, 0);writeU32(w, 0); //modified
483     writeU16(w, ttf->head->xmin);
484     writeU16(w, ttf->head->ymin);
485     writeU16(w, ttf->head->xmax);
486     writeU16(w, ttf->head->ymax);
487     writeU16(w, ttf->head->macStyle);
488     writeU16(w, ttf->head->lowest_readable_size);
489     writeS16(w, ttf->head->dir_hint);
490     writeS16(w, loca_size); //loca index size (32 bit)
491     writeS16(w, 0); //glyph data format
492 }
493 static void head_dump(ttf_t*ttf)
494 {
495     printf("head->flags: %d\n", ttf->head->flags);
496     printf("head->units_per_em: %d\n", ttf->head->units_per_em);
497     printf("head->xmin: %d\n", ttf->head->xmin);
498     printf("head->ymin: %d\n", ttf->head->ymin);
499     printf("head->xmax: %d\n", ttf->head->xmax);
500     printf("head->ymax: %d\n", ttf->head->ymax);
501     printf("head->macStyle: %d\n", ttf->head->macStyle);
502     printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
503     printf("head->dir_hint: %d\n", ttf->head->dir_hint);
504 }
505 static void head_delete(ttf_t*ttf)
506 {
507     if(ttf->head) {
508         free(ttf->head);
509         ttf->head=0;
510     }
511 }
512
513 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
514 {
515     U32 version = readU32(r);
516     ttf->num_glyphs = readU16(r);
517     /* according to freetype, older fonts (version<0x10000) 
518        apparently only contain the number of glyphs. this is
519        rather rare, though. */
520     if(version<0x10000) return 0;
521
522     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
523     maxp->maxPoints = readU16(r);
524     maxp->maxContours = readU16(r);
525     maxp->maxComponentPoints = readU16(r);
526     maxp->maxComponentContours = readU16(r);
527     maxp->maxZones = readU16(r);
528     maxp->maxTwilightPoints = readU16(r);
529     maxp->maxStorage = readU16(r);
530     maxp->maxFunctionDefs = readU16(r);
531     maxp->maxInstructionDefs = readU16(r);
532     maxp->maxStackElements = readU16(r);
533     maxp->maxSizeOfInstructions = readU16(r);
534     maxp->maxComponentElements = readU16(r);
535     maxp->maxComponentDepth = readU16(r);
536     return maxp;
537 }
538
539 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
540 {
541     table_maxp_t*maxp = ttf->maxp;
542     writeU32(w, 0x10000); //version
543     writeU16(w, ttf->num_glyphs);
544     writeU16(w, maxp->maxPoints);
545     writeU16(w, maxp->maxContours);
546     writeU16(w, maxp->maxComponentPoints);
547     writeU16(w, maxp->maxComponentContours);
548     writeU16(w, maxp->maxZones);
549     writeU16(w, maxp->maxTwilightPoints);
550     writeU16(w, maxp->maxStorage);
551     writeU16(w, maxp->maxFunctionDefs);
552     writeU16(w, maxp->maxInstructionDefs);
553     writeU16(w, maxp->maxStackElements);
554     writeU16(w, maxp->maxSizeOfInstructions);
555     writeU16(w, maxp->maxComponentElements);
556     writeU16(w, maxp->maxComponentDepth);
557 }
558
559 static void maxp_dump(ttf_t*ttf)
560 {
561     table_maxp_t*maxp = ttf->maxp;
562     if(!maxp) return;
563     printf("maxp->maxPoints: %d\n", maxp->maxPoints);
564     printf("maxp->maxContours: %d\n", maxp->maxContours);
565     printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
566     printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
567     printf("maxp->maxZones: %d\n", maxp->maxZones);
568     printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
569     printf("maxp->maxStorage: %d\n", maxp->maxStorage);
570     printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
571     printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
572     printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
573     printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
574     printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
575     printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
576 }
577
578 static void maxp_delete(ttf_t*ttf)
579 {
580     if(ttf->maxp)
581         free(ttf->maxp);
582     ttf->maxp=0;
583 }
584
585
586 static int hea_parse(memreader_t*r, ttf_t*ttf)
587 {
588     table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
589     U32 version = readU32(r);
590     hea->ascent = readS16(r);
591     hea->descent = readS16(r);
592     hea->lineGap = readS16(r);
593     hea->advanceWidthMax = readU16(r);
594     hea->minLeftSideBearing = readS16(r);
595     hea->minRightSideBearing = readS16(r);
596     hea->xMaxExtent = readS16(r);
597     hea->caretSlopeRise = readS16(r);
598     hea->caretSlopeRun = readS16(r);
599     hea->caretOffset = readS16(r);
600     readS16(r); //reserved[0]
601     readS16(r); //reserved[1]
602     readS16(r); //reserved[2]
603     readS16(r); //reserved[3]
604     S16 metricDataFormat = readS16(r); //should be 0
605     if(metricDataFormat!=0) {
606         msg("<warning> Unknown metric format %d", metricDataFormat);
607     }
608     int num_advances = readU16(r);
609     if(num_advances > ttf->num_glyphs) {
610         msg("<warning> bad number of horizontal metrics: %d", num_advances);
611         num_advances = ttf->num_glyphs;
612     }
613     return num_advances;
614 }
615
616 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
617 {
618     table_hea_t*hea = ttf->hea;
619     writeU32(w, 0x00010000);
620     writeS16(w, hea->ascent);
621     writeS16(w, hea->descent);
622     writeS16(w, hea->lineGap);
623     writeU16(w, hea->advanceWidthMax);
624     writeS16(w, hea->minLeftSideBearing);
625     writeS16(w, hea->minRightSideBearing);
626     writeS16(w, hea->xMaxExtent);
627     writeS16(w, hea->caretSlopeRise);
628     writeS16(w, hea->caretSlopeRun);
629     writeS16(w, hea->caretOffset);
630     writeS16(w, 0); //reserved
631     writeS16(w, 0); //reserved
632     writeS16(w, 0); //reserved
633     writeS16(w, 0); //reserved
634     writeS16(w, 0); //metricDataFormat
635     writeU16(w, num_advances);
636     return hea;
637 }
638 static void hea_dump(ttf_t*ttf)
639 {
640     table_hea_t*hea = ttf->hea;
641     const char*dir = ttf->is_vertical?"v":"h";
642     printf("%shea->ascent: %d\n", dir, hea->ascent);
643     printf("%shea->descent: %d\n", dir, hea->descent);
644     printf("%shea->lineGap: %d\n", dir, hea->lineGap);
645     printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
646     printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
647     printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
648     printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
649     printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
650     printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
651     printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
652 }
653 static void hea_delete(ttf_t*ttf)
654 {
655     if(ttf->hea) {
656         free(ttf->hea);
657         ttf->hea=0;
658     }
659 }
660
661 static void hmtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
662 {
663     U16 old_advance = 0;
664     int t;
665     if(num_advances > r->size/4)
666         num_advances = r->size/4;
667     for(t=0;t<num_advances;t++) {
668         old_advance = ttf->glyphs[t].advance = readU16(r);
669         ttf->glyphs[t].bearing = readS16(r);
670     }
671     int rest = (r->size - num_advances*4)/2;
672     if(ttf->num_glyphs < num_advances+rest) {
673         rest = ttf->num_glyphs-num_advances;
674     }
675     for(t=0;t<rest;t++) {
676         ttf->glyphs[t].advance = old_advance; 
677         ttf->glyphs[t].bearing = readS16(r);
678     }
679 }
680 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
681 {
682     int num_advances = ttf->num_glyphs;
683     if(ttf->num_glyphs>=2) {
684         int t;
685         for(t=ttf->num_glyphs-1;t>0;t--) {
686             if(ttf->glyphs[t-1].advance !=
687                ttf->glyphs[t].advance) break;
688         }
689         /* we need to store all individual advances as well
690            as one entry for the constant */
691         num_advances = t+1;
692     }
693
694     int t;
695     for(t=0;t<num_advances;t++) {
696         writeU16(w, ttf->glyphs[t].advance);
697         writeU16(w, ttf->glyphs[t].bearing);
698     }
699     for(;t<ttf->num_glyphs;t++) {
700         writeU16(w, ttf->glyphs[t].bearing);
701     }
702     return num_advances;
703 }
704 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
705 {
706     int t;
707     int num = ttf->num_glyphs+1;
708     U32*locations = rfx_calloc(num*sizeof(U32));
709     if(size) {
710         if(num*4 > r->size) {
711             msg("<warning> Short 'loca' table (32 bit)");
712             num=r->size/4;
713         }
714         if(num*4 < r->size) {
715             msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
716         }
717         for(t=0;t<num;t++) {
718             locations[t] = readU32(r);
719         }
720     } else {
721         if(num*2 > r->size) {
722             msg("<warning> Short 'loca' table (16 bit)");
723             num=r->size/2;
724         }
725         if(num*2 < r->size) {
726             msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
727         }
728         for(t=0;t<num;t++) {
729             locations[t] = readU16(r)*2;
730         }
731     }
732     return locations;
733 }
734 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
735 {
736     int t;
737     char use_32bit = 0;
738     for(t=0;t<=ttf->num_glyphs;t++) {
739         if(locations[t]>=0x20000 || (locations[t]&1)) {
740             use_32bit = 1;
741             break;
742         }
743     }
744
745     if(use_32bit) {
746         for(t=0;t<=ttf->num_glyphs;t++) {
747             writeU32(w, locations[t]);
748         }
749         return 1;
750     } else {
751         for(t=0;t<=ttf->num_glyphs;t++) {
752             writeU16(w, locations[t]/2);
753         }
754         return 0;
755     }
756 }
757 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
758 {
759     ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
760
761     U16*endpoints = 0;
762     if(num_contours>0) {
763         endpoints = malloc(sizeof(U16)*num_contours);
764         int s;
765         int lastpos = -1;
766         for(s=0;s<num_contours;s++) {
767             int pos = endpoints[s] = readU16(r);
768             if(pos<=lastpos) {
769                 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
770             }
771             lastpos = pos;
772         }
773     }
774     U16 code_len = readU16(r);
775     if(code_len) {
776         glyph->code = malloc(sizeof(U16)*code_len);
777         readBlock(r, glyph->code, code_len);
778         glyph->code_size = code_len;
779     }
780
781     if(!endpoints) 
782         return 1;
783
784     /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", 
785             glyphnr, code_len, num_contours, glyph->num_points,
786             xmin, ymin, xmax, ymax);*/
787     INIT_READ(fx, r->mem, r->size, r->pos);
788     INIT_READ(fy, r->mem, r->size, r->pos);
789     
790     glyph->num_points = endpoints[num_contours-1] + 1;
791     glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
792
793     /* parse flag array (1st pass- to determine start of coordinates) */
794     int num=0;
795     while(num<glyph->num_points) {
796         U8 flag = readU8(r);
797         if(flag&0xc0) {
798             msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
799             free(glyph->points);
800             glyph->points = 0;
801             glyph->num_points = 0;
802             return 0;
803         }
804         int count = 1;
805         if(flag & 0x08) 
806             count += readU8(r);
807         if(count+num>glyph->num_points) {
808             msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
809             count = glyph->num_points-num;
810         }
811         num+=count;
812     }
813
814     /* parse flag array (2nd pass) and x coordinates */
815     num=0;
816     int x = 0;
817     char is_start=1;
818     int contour_pos=0;
819     int bytepos = r->pos;
820     while(num<glyph->num_points) {
821         U8 flag = readU8(&fx);
822         int count = flag&8?readU8(&fx)+1:1;
823         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
824         do {
825             char is_end=0;
826             if(contour_pos<num_contours && num==endpoints[contour_pos]) {
827                 contour_pos++;
828                 is_end=1;
829             }
830             int oldx = x;
831             if((flag&0x12) == 0x12) x += readU8(r);
832             else if((flag&0x12) == 0x02) x -= readU8(r);
833             else if((flag&0x12) == 0x00) x += readS16(r);
834             
835             glyph->points[num].x = x;
836             U8 f = flag&GLYPH_ON_CURVE;
837             if(is_start) f|=GLYPH_CONTOUR_START;
838             if(is_end) f|=GLYPH_CONTOUR_END;
839             glyph->points[num].flags = f;
840             num++;
841             is_start = is_end;
842         } while(--count);
843     }
844     
845     /* parse flag array (3rd pass) and y coordinates */
846     num=0;
847     int y = 0;
848     while(num<glyph->num_points) {
849         U8 flag = readU8(&fy);
850         int count = flag&8?readU8(&fy)+1:1;
851         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
852         do {
853             if((flag&0x24) == 0x24) y += readU8(r);
854             else if((flag&0x24) == 0x04) y -= readU8(r);
855             else if((flag&0x24) == 0x00) y += readS16(r);
856             glyph->points[num].y = y;
857             num++;
858         } while(--count);
859     }
860     free(endpoints);
861     return 1;
862 }
863 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
864 {
865     int t;
866     char warn_about_compound_glyphs=1;
867     for(t=0;t<ttf->num_glyphs;t++) {
868         INIT_READ(r, rr->mem, rr->size, loca[t]);
869         if(r.pos+10>r.size) {
870             msg("<warning> Unexpected end of glyph array (or bad loca entry %d/%d)", loca[t], r.size);
871             break;
872         }
873         S16 num_contours = readS16(&r);
874         ttf->glyphs[t].xmin = readS16(&r);
875         ttf->glyphs[t].ymin = readS16(&r);
876         ttf->glyphs[t].xmax = readS16(&r);
877         ttf->glyphs[t].ymax = readS16(&r);
878         
879         if(num_contours<0) {
880             if(warn_about_compound_glyphs)
881                 msg("<error> Compound glyphs not supported yet");
882             warn_about_compound_glyphs=0;
883         } else {
884             if(!parse_simple_glyph(ttf, &r, num_contours, t))
885                 return;
886         }
887     }
888
889 }
890
891 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
892 {
893     /* endpoints array */
894     int s;
895     for(s=0;s<g->num_points;s++) {
896         if(g->points[s].flags&GLYPH_CONTOUR_END)
897             writeU16(w, s);
898     }
899     
900     /* bytecode */
901     writeU16(w, g->code_size);
902     if(g->code_size)
903         writeBlock(w, g->code, g->code_size);
904
905     /* flags */
906     int lastx=0;
907     int lasty=0;
908     int lastflag=-1;
909     int flagcount=0;
910     for(s=0;s<g->num_points;s++) {
911         ttfpoint_t*p = &g->points[s];
912         int dx = p->x - lastx;
913         int dy = p->y - lasty;
914         U8 flags = p->flags&GLYPH_ON_CURVE;
915         if(!dx) {
916             flags|=0x10;
917         } else if(dx<0 && dx>=-255) {
918             flags|=0x02;
919         } else if(dx>0 && dx<=255) {
920             flags|=0x12;
921         }
922         if(!dy) {
923             flags|=0x20;
924         } else if(dy<0 && dy>=-255) {
925             flags|=0x04;
926         } else if(dy>0 && dy<=255) {
927             flags|=0x24;
928         }
929         if(flags == lastflag && flagcount<255) {
930             flagcount++;
931         } else {
932             if(lastflag>=0) {
933                 if(flagcount) {
934                     writeU8(w, lastflag|8);
935                     writeU8(w, flagcount);
936                 } else {
937                     writeU8(w, lastflag);
938                 }
939             }
940             lastflag = flags;
941             flagcount = 0;
942         }
943         lastx = p->x;
944         lasty = p->y;
945     }
946     if(lastflag>=0) {
947         if(flagcount) {
948             writeU8(w, lastflag|8);
949             writeU8(w, flagcount);
950         } else {
951             writeU8(w, lastflag);
952         }
953     }
954     /* coordinates */
955     lastx=0;
956     int bytepos = w->len;
957     for(s=0;s<g->num_points;s++) {
958         ttfpoint_t*p = &g->points[s];
959         int dx = p->x - lastx;
960         if(dx>32767 || dx<-32768) {
961             msg("<error> Coordinate overflow in glyph");
962         }
963         lastx = p->x;
964         if(dx>0 && dx<=255) writeU8(w, dx);
965         else if(dx<0 && dx>=-255) writeU8(w, -dx);
966         else if(dx) writeS16(w, dx);
967     }
968
969     lasty=0;
970     for(s=0;s<g->num_points;s++) {
971         ttfpoint_t*p = &g->points[s];
972         int dy = p->y - lasty;
973         if(dy>32767 || dy<-32768) {
974             msg("<error> Coordinate overflow in glyph");
975         }
976         lasty = p->y;
977         if(dy>0 && dy<=255) writeU8(w, dy);
978         else if(dy<0 && dy>=-255) writeU8(w, -dy);
979         else if(dy) writeS16(w, dy);
980     }
981 }
982     
983 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
984 {
985     U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
986     int t;
987     for(t=0;t<ttf->num_glyphs;t++) {
988         locations[t] = w->len;
989         ttfglyph_t*g = &ttf->glyphs[t];
990         int s;
991         int num_contours = 0;
992         for(s=0;s<g->num_points;s++) {
993             if(g->points[s].flags&GLYPH_CONTOUR_END)
994                 num_contours++;
995         }
996         writeS16(w, num_contours?num_contours:1);
997         writeS16(w, g->xmin);
998         writeS16(w, g->ymin);
999         writeS16(w, g->xmax);
1000         writeS16(w, g->ymax);
1001         
1002         if(!num_contours) {
1003             /* some ttf parsers can't deal with zero contours, so in the case
1004                of an empty glyph, write a single point (0,0) */
1005             writeU16(w, 0); //endpoint of 1st contour
1006             writeU16(w, g->code_size);
1007             if(g->code_size)
1008                 writeBlock(w, g->code, g->code_size);
1009             writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1010         } else {
1011             write_simple_glyph(w, g);
1012         }
1013     }
1014     locations[t] = w->len;
1015     return locations;
1016 }
1017 void glyf_dump(ttf_t* ttf)
1018 {
1019     int t;
1020     for(t=0;t<ttf->num_glyphs;t++) {
1021         ttfglyph_t*g = &ttf->glyphs[t];
1022         printf("glyph %d)\n", t);
1023         printf("  advance=%d\n", g->advance);
1024         printf("  bearing=%d\n", g->bearing);
1025         printf("  bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1026         printf("  points=(");
1027         int s;
1028         for(s=0;s<g->num_points;s++) {
1029             if(s) printf(",");
1030             printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1031         }
1032         printf(")\n");
1033         if(g->code_size) 
1034             hexdump(g->code, g->code_size, "  ");
1035     }
1036 }
1037
1038 void glyf_delete(ttf_t* ttf)
1039 {
1040     if(!ttf->glyphs) 
1041         return;
1042     int t;
1043     for(t=0;t<ttf->num_glyphs;t++) {
1044         if(ttf->glyphs[t].code) {
1045             free(ttf->glyphs[t].code);
1046             ttf->glyphs[t].code = 0;
1047         }
1048         if(ttf->glyphs[t].points) {
1049             free(ttf->glyphs[t].points);
1050             ttf->glyphs[t].points = 0;
1051         }
1052     }
1053     free(ttf->glyphs);ttf->glyphs=0;
1054 }
1055
1056 static int ttf_parse_tables(ttf_t*ttf)
1057 {
1058     ttf_table_t*table;
1059
1060     table = ttf_find_table(ttf, TAG_HEAD);
1061     if(!table) {
1062         msg("<error> Font has no head table");
1063         return 0;
1064     }
1065     INIT_READ(m, table->data, table->len, 0);
1066     int loc_index = head_parse(ttf, &m);
1067     ttf_table_delete(ttf, table);
1068     
1069     table = ttf_find_table(ttf, TAG_MAXP);
1070     if(!table) {
1071         msg("<error> Font has no maxp table");
1072         return 0;
1073     }
1074     INIT_READ(m2, table->data, table->len, 0);
1075     ttf->maxp = maxp_parse(ttf, &m2);
1076     ttf_table_delete(ttf, table);
1077     
1078     if(!ttf->num_glyphs) {
1079         msg("<error> Invalid number of characters");
1080         return 0;
1081     }
1082     ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1083
1084     table = ttf_find_table(ttf, TAG_OS2);
1085     if(table) {
1086         INIT_READ(m, table->data, table->len, 0);
1087         ttf->os2 = os2_parse(&m);
1088         ttf_table_delete(ttf, table);
1089     }
1090
1091     table = ttf_find_table(ttf, TAG_HHEA);
1092     if(table) {
1093         INIT_READ(m, table->data, table->len, 0);
1094         int num_advances = hea_parse(&m, ttf);
1095         ttf_table_delete(ttf, table);
1096         
1097         table = ttf_find_table(ttf, TAG_HMTX);
1098         if(table) {
1099             INIT_READ(m, table->data, table->len, 0);
1100             hmtx_parse(&m, ttf, num_advances);
1101             ttf_table_delete(ttf, table);
1102         }
1103     } else {
1104         table = ttf_find_table(ttf, TAG_VHEA);
1105         if(table) {
1106             ttf->is_vertical=1;
1107             INIT_READ(m, table->data, table->len, 0);
1108             int num_advances = hea_parse(&m, ttf);
1109             ttf_table_delete(ttf, table);
1110
1111             table = ttf_find_table(ttf, TAG_VMTX);
1112             if(table) {
1113                 INIT_READ(m, table->data, table->len, 0);
1114                 hmtx_parse(&m, ttf, num_advances);
1115                 ttf_table_delete(ttf, table);
1116             }
1117         } else {
1118             msg("<error> Font contains neither HHEA nor VHEA");
1119         }
1120     }
1121     table = ttf_find_table(ttf, TAG_LOCA);
1122     if(table) {
1123         INIT_READ(m, table->data, table->len, 0);
1124         U32*loca = loca_parse(&m, ttf, loc_index);
1125         ttf_table_delete(ttf, table);
1126         table = ttf_find_table(ttf, TAG_GLYF);
1127         if(table) {
1128             INIT_READ(m, table->data, table->len, 0);
1129             glyf_parse(&m, ttf, loca);
1130             ttf_table_delete(ttf, table);
1131         }
1132         free(loca);
1133     }
1134     return 1;
1135 }
1136 static void ttf_collapse_tables(ttf_t*ttf)
1137 {
1138     ttf_table_t*table;
1139     
1140     table = ttf_addtable(ttf, TAG_MAXP);
1141     maxp_write(ttf, table);
1142     maxp_delete(ttf);
1143
1144     table = ttf_addtable(ttf, TAG_OS2);
1145     os2_write(ttf, table);
1146     os2_delete(ttf);
1147
1148     if(!ttf->is_vertical) {
1149         table = ttf_addtable(ttf, TAG_HMTX);
1150         int num_advances = mtx_write(ttf, table);
1151         table = ttf_addtable(ttf, TAG_HHEA);
1152         hea_write(ttf, table, num_advances);
1153     } else {
1154         table = ttf_addtable(ttf, TAG_VMTX);
1155         int num_advances = mtx_write(ttf, table);
1156         table = ttf_addtable(ttf, TAG_VHEA);
1157         hea_write(ttf, table, num_advances);
1158     }
1159
1160     int loca_size=0;
1161     if(ttf->num_glyphs) {
1162         table = ttf_addtable(ttf, TAG_GLYF);
1163         U32*locations = glyf_write(ttf, table);
1164         glyf_delete(ttf);
1165         
1166         table = ttf_addtable(ttf, TAG_LOCA);
1167         loca_size = loca_write(ttf, table, locations);
1168         free(locations);
1169     }
1170     
1171     table = ttf_addtable(ttf, TAG_HEAD);
1172     head_write(ttf, table, loca_size);
1173     head_delete(ttf);
1174
1175 }
1176
1177 ttf_t* load_ttf(void*data, int length)
1178 {
1179     INIT_READ(r,data,length, 0);
1180
1181     if(length<12) {
1182         msg("<error> Truncated Truetype file (%d bytes)", length);
1183         return 0;
1184     }
1185
1186     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1187     ttf->version = readU32(&r);
1188     if(ttf->version == TTCFTAG) {
1189         /* a ttc collection is a number of truetype fonts
1190            packaged together */
1191         if(length<16) {
1192             msg("<error> Truncated TTC file (%d bytes)", length);
1193             return 0;
1194         }
1195         U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1196         U32 num_fonts = readU32(&r); // number of fonts
1197         U32 font1_position = readU32(&r);
1198         if(font1_position+12 > length) {\
1199             msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1200             return 0;
1201         }
1202         r.pos = font1_position;
1203         ttf->version = readU32(&r);
1204     }
1205     
1206     int num_tables = readU16(&r);
1207     
1208     readU16(&r); //search range
1209     readU16(&r); //entry selector
1210     readU16(&r); //range shift
1211
1212     if(num_tables*16 > length) {
1213         msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1214         if(ttf->version != OPENTYPE && 
1215            ttf->version != TRUETYPE_MACOS && 
1216            ttf->version != VERSION_1_0) {
1217             // bad table length, weird version. This is probably not a ttf file.
1218             return 0;
1219         }
1220     }
1221
1222     U32*table_data = malloc(16*num_tables);
1223     int t;
1224     for(t=0;t<num_tables*4;t++) {
1225         table_data[t] = readU32(&r);
1226     }
1227     for(t=0;t<num_tables;t++) {
1228         U32 tag = table_data[t*4];
1229         U32 checksum = table_data[t*4+1];
1230         U32 pos = table_data[t*4+2];
1231         U32 len = table_data[t*4+3];
1232
1233         if(pos+len > length) {
1234             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);
1235         } else {
1236             U8*mem = malloc(len);
1237             r.pos = pos;
1238             readBlock(&r, mem, len);
1239             
1240             ttf_table_t*table = ttf_addtable(ttf, tag);
1241             table->data = mem;
1242             table->len = table->memsize = len;
1243             
1244             U32 checksum2 = ttf_table_checksum(table);
1245             if(checksum2!=checksum) {
1246                 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
1247                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1248                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1249                         len, checksum2, checksum);
1250             }
1251             
1252         }
1253     }
1254     free(table_data);
1255
1256     if(!ttf_parse_tables(ttf)) 
1257         return 0;
1258
1259     return ttf;
1260 }
1261
1262 ttf_table_t* ttf_write(ttf_t*ttf)
1263 {
1264     ttf_collapse_tables(ttf);
1265    
1266     ttf_table_t*file = ttf_table_new(0);
1267     writeU32(file, VERSION_1_0);
1268
1269     /* write number of tables */
1270     int num_tables=0;
1271     ttf_table_t*t = ttf->tables;
1272     while(t) {
1273         num_tables++;
1274         t = t->next;
1275     }
1276     writeU16(file, num_tables);
1277     
1278     /* write search range */
1279     int tmp = num_tables;
1280     int search_range = 0;
1281     while(tmp) {
1282         search_range = tmp;
1283         tmp = tmp&(tmp-1);
1284     }
1285     tmp = search_range;
1286     search_range*=16;
1287     writeU16(file, search_range);
1288
1289     /* write entry selector */
1290     int entry_selector = 0;
1291     while(tmp>1) {
1292         tmp>>=1;
1293         entry_selector++;
1294     }
1295     writeU16(file, entry_selector);
1296
1297     /* write range shift */
1298     int range_shift = num_tables*16 - search_range;
1299     writeU16(file, range_shift);
1300
1301     /* write table dictionary */
1302     int table_dictionary_pos = file->len;
1303     int data_pos = file->len + num_tables*16;
1304     for(t=ttf->tables;t;t=t->next) {
1305         writeU32(file, t->id);
1306         writeU32(file, ttf_table_checksum(t));
1307         writeU32(file, data_pos);
1308         writeU32(file, t->len);
1309         data_pos += t->len;
1310         data_pos += (-t->len)&3; //pad
1311     }
1312
1313     /* write tables */
1314     int head_pos = 0;
1315     U8 zero[4]={0,0,0,0};
1316     for(t=ttf->tables;t;t=t->next) {
1317         if(t->id == TAG_HEAD)
1318             head_pos = file->len;
1319         writeBlock(file, t->data, t->len);
1320         writeBlock(file, zero, (-t->len)&3); //pad
1321     }
1322     U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1323     U8*checksum2 = file->data + head_pos + 8;
1324     checksum2[0] = checksum>>24;
1325     checksum2[1] = checksum>>16;
1326     checksum2[2] = checksum>>8;
1327     checksum2[3] = checksum>>0;
1328     return file;
1329 }
1330
1331 void ttf_save(ttf_t*ttf, const char*filename)
1332 {
1333     ttf_table_t* t = ttf_write(ttf);
1334     FILE*fi = fopen(filename, "wb");
1335     if(!fi) {
1336         perror(filename);
1337         return;
1338     }
1339     fwrite(t->data, t->len, 1, fi);
1340     fclose(fi);
1341     ttf_table_delete(0, t);
1342 }
1343
1344 void ttf_dump(ttf_t*ttf)
1345 {
1346     msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1347     ttf_table_t*table = ttf->tables;
1348     while(table) {
1349         U32 tag = table->id;
1350         msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", 
1351                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, 
1352                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1353         table = table->next;
1354     }
1355     //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1356
1357     head_dump(ttf);
1358     hea_dump(ttf);
1359     os2_dump(ttf);
1360     maxp_dump(ttf);
1361     glyf_dump(ttf);
1362 }
1363 void ttf_destroy(ttf_t*ttf)
1364 {
1365     ttf_table_t*table = ttf->tables;
1366     while(table) {
1367         ttf_table_t*next = table->next;
1368         free(table->data);
1369         free(table);
1370         table = next;
1371     }
1372     maxp_delete(ttf);
1373     os2_delete(ttf);
1374     head_delete(ttf);
1375     hea_delete(ttf);
1376     glyf_delete(ttf);
1377     free(ttf);
1378 }
1379
1380 #ifdef MAIN
1381 int main(int argn, const char*argv[])
1382 {
1383     setConsoleLogging(7);
1384     const char*filename = "comic.ttf";
1385     if(argn>1) 
1386         filename = argv[1];
1387     //msg("<notice> Loading %s", filename);
1388     memfile_t*m = memfile_open(filename);
1389     ttf_t*ttf = load_ttf(m->data, m->len);
1390     if(!ttf) return 1;
1391     memfile_close(m);
1392     ttf_dump(ttf);
1393     //printf("os2 version: %04x (%d), maxp size: %d\n", 
1394 //          ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1395     ttf_save(ttf, "comic2.ttf");
1396     ttf_destroy(ttf);
1397     return 0;
1398
1399 }
1400 #endif