small bug in ttf reading
[swftools.git] / lib / ttf.c
index a5bcfe4..c1fd06d 100644 (file)
--- a/lib/ttf.c
+++ b/lib/ttf.c
 #define TAG_NAME 0x6e616d65
 #define TAG_POST 0x706f7374
 #define TAG_CFF  0x43464620 //required for opentype
 #define TAG_NAME 0x6e616d65
 #define TAG_POST 0x706f7374
 #define TAG_CFF  0x43464620 //required for opentype
+#define TAG_CVT  0x63767420 
+#define TAG_FPGM 0x6670676d 
+#define TAG_GASP 0x67617370 
+#define TAG_PREP 0x70726570 
 
 
-/* TODO:
-    fpgm - assembly instructions
-    prep - assembly instructions
-    cvt - constant value table
-    gasp - gridfitting procedure
-*/
 
 static U32 checksum_block(U8*_data, int len)
 {
 
 static U32 checksum_block(U8*_data, int len)
 {
@@ -118,7 +116,7 @@ static void readBlock(memreader_t*r, void*dest, int len)
        r->pos += len;
     }
 }
        r->pos += len;
     }
 }
-static void reader_reset(memreader_t*r) 
+static void reader_reset(memreader_t*r)
 {
     r->pos;
 }
 {
     r->pos;
 }
@@ -200,7 +198,7 @@ ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
        before->len = 0;
        return before;
     }
        before->len = 0;
        return before;
     }
-    
+
     if(!after) {
        t->next = ttf->tables;
        ttf->tables = t;
     if(!after) {
        t->next = ttf->tables;
        ttf->tables = t;
@@ -217,7 +215,7 @@ ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
 {
     ttf_table_t*table = ttf->tables;
     while(table) {
 {
     ttf_table_t*table = ttf->tables;
     while(table) {
-       if(table->id == id) 
+       if(table->id == id)
            return table;
        table = table->next;
     }
            return table;
        table = table->next;
     }
@@ -228,9 +226,9 @@ void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
     if(ttf && ttf->tables == table) {
        ttf->tables = table->next;
     }
     if(ttf && ttf->tables == table) {
        ttf->tables = table->next;
     }
-    if(table->prev) 
+    if(table->prev)
        table->prev->next = table->next;
        table->prev->next = table->next;
-    if(table->next) 
+    if(table->next)
        table->next->prev = table->prev;
     free(table->data);
     free(table);
        table->next->prev = table->prev;
     free(table->data);
     free(table);
@@ -305,12 +303,12 @@ static int head_parse(ttf_t*ttf, memreader_t*r)
 {
     ttf->head = rfx_calloc(sizeof(table_head_t));
     U32 version = readU32(r);
 {
     ttf->head = rfx_calloc(sizeof(table_head_t));
     U32 version = readU32(r);
-    if(version!=VERSION_1_0) 
+    if(version!=VERSION_1_0)
        msg("<warning> Font HEAD has unknown version %08x", version);
     U32 revision = readU32(r);
     U32 checksum2 = readU32(r);
     U32 magic = readU32(r);
        msg("<warning> Font HEAD has unknown version %08x", version);
     U32 revision = readU32(r);
     U32 checksum2 = readU32(r);
     U32 magic = readU32(r);
-    if(magic!=0x5f0f3cf5) 
+    if(magic!=0x5f0f3cf5)
        msg("<warning> Font HEAD has unknown magic number %08x", magic);
     ttf->head->flags = readU16(r);
     ttf->head->units_per_em = readU16(r);
        msg("<warning> Font HEAD has unknown magic number %08x", magic);
     ttf->head->flags = readU16(r);
     ttf->head->units_per_em = readU16(r);
@@ -389,7 +387,7 @@ static table_os2_t*os2_new(ttf_t*ttf)
     /* that's what everybody seems to fill in */
     os2->usWeightClass = 400;
     os2->usWidthClass = 5;
     /* that's what everybody seems to fill in */
     os2->usWeightClass = 400;
     os2->usWidthClass = 5;
-   
+
     if(ttf->head) {
        int advance = (ttf->head->xmax - ttf->head->xmin)/2;
        int height = (ttf->head->xmax - ttf->head->xmin);
     if(ttf->head) {
        int advance = (ttf->head->xmax - ttf->head->xmin)/2;
        int height = (ttf->head->xmax - ttf->head->xmin);
@@ -405,8 +403,8 @@ static table_os2_t*os2_new(ttf_t*ttf)
        os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
        os2->yStrikeoutSize = ttf->head->units_per_em / 10;
        os2->yStrikeoutPosition = ymid;
        os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
        os2->yStrikeoutSize = ttf->head->units_per_em / 10;
        os2->yStrikeoutPosition = ymid;
-       os2->usWinAscent = ttf->head->ymax;
-       os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
+       os2->usWinAscent = ttf->ascent;
+       os2->usWinDescent = ttf->descent>0?0:-ttf->descent;
        os2->sxHeight = ymid;
        os2->sCapHeight = height*2/3;
     }
        os2->sxHeight = ymid;
        os2->sCapHeight = height*2/3;
     }
@@ -498,7 +496,7 @@ static table_os2_t*os2_parse(memreader_t*r)
     os2->usDefaultChar = readU16(r);
     os2->usBreakChar = readU16(r);
     os2->usMaxContext = readU16(r);
     os2->usDefaultChar = readU16(r);
     os2->usBreakChar = readU16(r);
     os2->usMaxContext = readU16(r);
-    
+
     if(r->pos < r->size) {
        msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
     }
     if(r->pos < r->size) {
        msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
     }
@@ -640,13 +638,14 @@ static table_maxp_t*maxp_new(ttf_t*ttf)
        maxp->maxComponentPoints = 0;
        maxp->maxComponentContours = 0;
     }
        maxp->maxComponentPoints = 0;
        maxp->maxComponentContours = 0;
     }
+    maxp->maxZones = 2; // we don't use the Z0 zone
     return maxp;
 }
 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
 {
     U32 version = readU32(r);
     ttf->num_glyphs = readU16(r);
     return maxp;
 }
 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
 {
     U32 version = readU32(r);
     ttf->num_glyphs = readU16(r);
-    /* according to freetype, older fonts (version<0x10000) 
+    /* according to freetype, older fonts (version<0x10000)
        apparently only contain the number of glyphs. this is
        rather rare, though. */
     if(version<0x10000 && r->size==6) return 0;
        apparently only contain the number of glyphs. this is
        rather rare, though. */
     if(version<0x10000 && r->size==6) return 0;
@@ -728,15 +727,15 @@ static table_hea_t*hea_new(ttf_t*ttf)
        for(t=0;t<ttf->num_glyphs;t++) {
            if(ttf->glyphs[t].advance > hea->advanceWidthMax)
                hea->advanceWidthMax = ttf->glyphs[t].advance;
        for(t=0;t<ttf->num_glyphs;t++) {
            if(ttf->glyphs[t].advance > hea->advanceWidthMax)
                hea->advanceWidthMax = ttf->glyphs[t].advance;
-           if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
-               hea->minLeftSideBearing = ttf->glyphs[t].xmin;
+           if(ttf->glyphs[t].bearing < hea->minLeftSideBearing)
+               hea->minLeftSideBearing = ttf->glyphs[t].bearing;
            if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
                hea->minRightSideBearing = ttf->glyphs[t].xmax;
            int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
            if(width > hea->xMaxExtent)
                hea->xMaxExtent = width;
        }
            if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
                hea->minRightSideBearing = ttf->glyphs[t].xmax;
            int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
            if(width > hea->xMaxExtent)
                hea->xMaxExtent = width;
        }
-       /* TODO: caret */
+       hea->caretSlopeRise = 1;
     }
     return hea;
 }
     }
     return hea;
 }
@@ -830,7 +829,7 @@ static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
        rest = ttf->num_glyphs-num_advances;
     }
     for(t=0;t<rest;t++) {
        rest = ttf->num_glyphs-num_advances;
     }
     for(t=0;t<rest;t++) {
-       ttf->glyphs[t].advance = old_advance; 
+       ttf->glyphs[t].advance = old_advance;
        ttf->glyphs[t].bearing = readS16(r);
     }
 }
        ttf->glyphs[t].bearing = readS16(r);
     }
 }
@@ -851,10 +850,10 @@ static int mtx_write(ttf_t*ttf, ttf_table_t*w)
     int t;
     for(t=0;t<num_advances;t++) {
        writeU16(w, ttf->glyphs[t].advance);
     int t;
     for(t=0;t<num_advances;t++) {
        writeU16(w, ttf->glyphs[t].advance);
-       writeU16(w, ttf->glyphs[t].bearing);
+       writeS16(w, ttf->glyphs[t].bearing);
     }
     for(;t<ttf->num_glyphs;t++) {
     }
     for(;t<ttf->num_glyphs;t++) {
-       writeU16(w, ttf->glyphs[t].bearing);
+       writeS16(w, ttf->glyphs[t].bearing);
     }
     return num_advances;
 }
     }
     return num_advances;
 }
@@ -950,15 +949,15 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl
        glyph->code_size = code_len;
     }
 
        glyph->code_size = code_len;
     }
 
-    if(!endpoints) 
+    if(!endpoints)
        return 1;
 
        return 1;
 
-    /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", 
+    /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
            glyphnr, code_len, num_contours, glyph->num_points,
            xmin, ymin, xmax, ymax);*/
     INIT_READ(fx, r->mem, r->size, r->pos);
     INIT_READ(fy, r->mem, r->size, r->pos);
            glyphnr, code_len, num_contours, glyph->num_points,
            xmin, ymin, xmax, ymax);*/
     INIT_READ(fx, r->mem, r->size, r->pos);
     INIT_READ(fy, r->mem, r->size, r->pos);
-    
+
     glyph->num_points = endpoints[num_contours-1] + 1;
     glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
 
     glyph->num_points = endpoints[num_contours-1] + 1;
     glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
 
@@ -974,7 +973,7 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl
            return 0;
        }
        int count = 1;
            return 0;
        }
        int count = 1;
-       if(flag & 0x08) 
+       if(flag & 0x08)
            count += readU8(r);
        if(count+num>glyph->num_points) {
            msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
            count += readU8(r);
        if(count+num>glyph->num_points) {
            msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
@@ -1003,7 +1002,7 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl
            if((flag&0x12) == 0x12) x += readU8(r);
            else if((flag&0x12) == 0x02) x -= readU8(r);
            else if((flag&0x12) == 0x00) x += readS16(r);
            if((flag&0x12) == 0x12) x += readU8(r);
            else if((flag&0x12) == 0x02) x -= readU8(r);
            else if((flag&0x12) == 0x00) x += readS16(r);
-           
+
            glyph->points[num].x = x;
            U8 f = flag&GLYPH_ON_CURVE;
            if(is_start) f|=GLYPH_CONTOUR_START;
            glyph->points[num].x = x;
            U8 f = flag&GLYPH_ON_CURVE;
            if(is_start) f|=GLYPH_CONTOUR_START;
@@ -1013,7 +1012,7 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl
            is_start = is_end;
        } while(--count);
     }
            is_start = is_end;
        } while(--count);
     }
-    
+
     /* parse flag array (3rd pass) and y coordinates */
     num=0;
     int y = 0;
     /* parse flag array (3rd pass) and y coordinates */
     num=0;
     int y = 0;
@@ -1041,7 +1040,7 @@ static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
        if(loca[t]==loca[t+1] || loca[t]==r.size)
            continue; //empty glyph
        if(r.pos+10>r.size) {
        if(loca[t]==loca[t+1] || loca[t]==r.size)
            continue; //empty glyph
        if(r.pos+10>r.size) {
-           msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", 
+           msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
                    t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
            break;
        }
                    t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
            break;
        }
@@ -1050,7 +1049,7 @@ static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
        ttf->glyphs[t].ymin = readS16(&r);
        ttf->glyphs[t].xmax = readS16(&r);
        ttf->glyphs[t].ymax = readS16(&r);
        ttf->glyphs[t].ymin = readS16(&r);
        ttf->glyphs[t].xmax = readS16(&r);
        ttf->glyphs[t].ymax = readS16(&r);
-       
+
        if(num_contours<0) {
            if(warn_about_compound_glyphs)
                msg("<error> Compound glyphs not supported yet");
        if(num_contours<0) {
            if(warn_about_compound_glyphs)
                msg("<error> Compound glyphs not supported yet");
@@ -1070,7 +1069,7 @@ void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
        if(g->points[s].flags&GLYPH_CONTOUR_END)
            writeU16(w, s);
     }
        if(g->points[s].flags&GLYPH_CONTOUR_END)
            writeU16(w, s);
     }
-    
+
     /* bytecode */
     writeU16(w, g->code_size);
     if(g->code_size)
     /* bytecode */
     writeU16(w, g->code_size);
     if(g->code_size)
@@ -1171,7 +1170,7 @@ U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
        writeS16(w, g->ymin);
        writeS16(w, g->xmax);
        writeS16(w, g->ymax);
        writeS16(w, g->ymin);
        writeS16(w, g->xmax);
        writeS16(w, g->ymax);
-       
+
        if(!num_contours) {
            /* some ttf parsers can't deal with zero contours, so in the case
               of an empty glyph, write a single point (0,0) */
        if(!num_contours) {
            /* some ttf parsers can't deal with zero contours, so in the case
               of an empty glyph, write a single point (0,0) */
@@ -1204,13 +1203,13 @@ void glyf_dump(ttf_t* ttf)
            printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
        }
        printf(")\n");
            printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
        }
        printf(")\n");
-       if(g->code_size) 
+       if(g->code_size)
            hexdump(g->code, g->code_size, "  ");
     }
 }
 void glyf_delete(ttf_t* ttf)
 {
            hexdump(g->code, g->code_size, "  ");
     }
 }
 void glyf_delete(ttf_t* ttf)
 {
-    if(!ttf->glyphs) 
+    if(!ttf->glyphs)
        return;
     int t;
     for(t=0;t<ttf->num_glyphs;t++) {
        return;
     int t;
     for(t=0;t<ttf->num_glyphs;t++) {
@@ -1261,7 +1260,7 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
                         platform==3 && encoding == 1 ||
                         platform==3 && encoding == 10;
 
                         platform==3 && encoding == 1 ||
                         platform==3 && encoding == 10;
 
-       if(!is_unicode) 
+       if(!is_unicode)
            continue;
 
        INIT_READ(t, r->mem, r->size, offset);
            continue;
 
        INIT_READ(t, r->mem, r->size, offset);
@@ -1286,7 +1285,7 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
                ttf->unicode[s] = readU8(&t);
            }
        } else if(format == 4) {
                ttf->unicode[s] = readU8(&t);
            }
        } else if(format == 4) {
-           U16 segment_count = readU16(&t); 
+           U16 segment_count = readU16(&t);
            if(segment_count&1) {
                msg("<error> Bad segmentx2 count %d", segment_count);
                continue;
            if(segment_count&1) {
                msg("<error> Bad segmentx2 count %d", segment_count);
                continue;
@@ -1308,8 +1307,8 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
                U16 delta = readU16(&r_delta);
                U16 range = readU16(&r_range);
                if(start==0xffff && end==0xffff && delta==1) {
                U16 delta = readU16(&r_delta);
                U16 range = readU16(&r_range);
                if(start==0xffff && end==0xffff && delta==1) {
-                   /* this is a common (maybe even required) occurence in fonts 
-                      which explicitly map "unicode undefined" (0xffff) to 
+                   /* this is a common (maybe even required) occurence in fonts
+                      which explicitly map "unicode undefined" (0xffff) to
                       "glyph undefined" (0).
                       We don't want to blow our unicode table up to 65536 just
                       because of this, so ignore this entry.
                       "glyph undefined" (0).
                       We don't want to blow our unicode table up to 65536 just
                       because of this, so ignore this entry.
@@ -1345,7 +1344,7 @@ static int segment_size(unicode_t*unicode, int pos, int size)
        if(!unicode[s])
            count++;
        if(count>4) {
        if(!unicode[s])
            count++;
        if(count>4) {
-           /* a segment costs us 8 bytes, so for more than 4 consecutive 
+           /* a segment costs us 8 bytes, so for more than 4 consecutive
               zero entries (16 bit each) in the glyph index array,
               it pays off to start a new segment */
            break;
               zero entries (16 bit each) in the glyph index array,
               it pays off to start a new segment */
            break;
@@ -1394,7 +1393,7 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
     num_segments++; // account for 0xffff mapping
 
     int glyphmap_start = w->len+2+num_segments*8;
     num_segments++; // account for 0xffff mapping
 
     int glyphmap_start = w->len+2+num_segments*8;
-    
+
     int t;
     int end_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
     int t;
     int end_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
@@ -1405,10 +1404,30 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
     int range_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
     int range_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
-           
-    w->data[num_segments_pos]=(num_segments*2)>>8;
-    w->data[num_segments_pos+1]=(num_segments*2);
-    
+
+    /* backpatch number of segments */
+    w->data[num_segments_pos++]=(num_segments*2)>>8;
+    w->data[num_segments_pos++]=(num_segments*2);
+    /* backpatch search range */
+    int tmp = num_segments;
+    int search_range = 0;
+    while(tmp) {
+       search_range = tmp;
+       tmp = tmp&(tmp-1);
+    }
+    w->data[num_segments_pos++]=(search_range*2)>>8;
+    w->data[num_segments_pos++]=(search_range*2);
+    /* backpatch entry selector */
+    int entry_selector = 0;
+    tmp = search_range;
+    while(tmp>1) {tmp>>=1;entry_selector++;}
+    w->data[num_segments_pos++]=entry_selector>>8;
+    w->data[num_segments_pos++]=entry_selector;
+    /* backpatch range shift */
+    int range_shift = num_segments*2 - search_range*2;
+    w->data[num_segments_pos++]=range_shift>>8;
+    w->data[num_segments_pos++]=range_shift;
+
     pos=0;
     num_segments = 0;
     while(pos < ttf->unicode_size) {
     pos=0;
     num_segments = 0;
     while(pos < ttf->unicode_size) {
@@ -1483,7 +1502,7 @@ void name_parse(memreader_t*r, ttf_t*ttf)
     U16 format = readU16(r);
     U16 count = readU16(r);
     U16 offset = readU16(r);
     U16 format = readU16(r);
     U16 count = readU16(r);
     U16 offset = readU16(r);
-   
+
     int t;
     for(t=0;t<count;t++) {
        U16 platform = readU16(r);
     int t;
     for(t=0;t<count;t++) {
        U16 platform = readU16(r);
@@ -1492,72 +1511,96 @@ void name_parse(memreader_t*r, ttf_t*ttf)
        U16 name_id = readU16(r);
        U16 len = readU16(r);
        U16 offset_2 = readU16(r);
        U16 name_id = readU16(r);
        U16 len = readU16(r);
        U16 offset_2 = readU16(r);
-       
+
+       char ** read_name = 0;
+
        INIT_READ(ss, r->mem, r->size, offset+offset_2);
        if(!(platform==0 || (platform==1 && encoding==0)))
                continue;
 
        INIT_READ(s, r->mem, r->size, offset+offset_2);
 
        INIT_READ(ss, r->mem, r->size, offset+offset_2);
        if(!(platform==0 || (platform==1 && encoding==0)))
                continue;
 
        INIT_READ(s, r->mem, r->size, offset+offset_2);
 
-       if(name_id==1) {
-           if(ttf->family_name) free(ttf->family_name);
-           ttf->family_name = readString(&s, len);
-       }
-       if(name_id==2) {
-           if(ttf->subfamily_name) free(ttf->subfamily_name);
-           ttf->subfamily_name = readString(&s, len);
+       switch (name_id) {
+           case 1: read_name = &ttf->family_name; break;
+           case 2: read_name = &ttf->subfamily_name; break;
+           case 3: read_name = &ttf->font_uid; break;
+           case 4: read_name = &ttf->full_name; break;
+           case 5: read_name = &ttf->version_string; break;
+           case 6: read_name = &ttf->postscript_name; break;
+           default: read_name = 0;
        }
        }
-       if(name_id==3) {
-           if(ttf->version_string) free(ttf->version_string);
-           ttf->version_string = readString(&s, len);
-       }
-       if(name_id==4) {
-           if(ttf->full_name) free(ttf->full_name);
-           ttf->full_name = readString(&s, len);
+
+       if (read_name) {
+           if (*read_name) free(*read_name);
+           *read_name = readString(&s, len);
        }
     }
 }
 void name_write(ttf_t*ttf, ttf_table_t*table)
 {
        }
     }
 }
 void name_write(ttf_t*ttf, ttf_table_t*table)
 {
-    char*strings[4] = {ttf->full_name, ttf->family_name, ttf->subfamily_name, ttf->version_string};
-    int codes[4] = {4,1,2,3};
+    char*strings[6] = {ttf->family_name, ttf->subfamily_name, ttf->font_uid, ttf->full_name, ttf->version_string, ttf->postscript_name};
+    int codes[6] = {1,2,3,4,5,6};
 
     writeU16(table, 0); //format
     int count = 0;
     int t;
     int nr = sizeof(strings)/sizeof(strings[0]);
 
     writeU16(table, 0); //format
     int count = 0;
     int t;
     int nr = sizeof(strings)/sizeof(strings[0]);
-    
+
     for(t=0;t<nr;t++) {
        if(strings[t])
     for(t=0;t<nr;t++) {
        if(strings[t])
-           count++;
+           count+=2;
     }
     writeU16(table, count); //count
 
     int offset_pos = table->len;
     writeU16(table, 0); //offset (will be filled in later)
 
     }
     writeU16(table, count); //count
 
     int offset_pos = table->len;
     writeU16(table, 0); //offset (will be filled in later)
 
+    /* Windows expects the name table to be sorted by platform/encoding/language/name_id */
     int offset = 0;
     int offset = 0;
-    for(t=0;t<nr;t++) { 
+    for(t=0;t<nr;t++) {
        if(strings[t]) {
        if(strings[t]) {
-           writeU16(table, 1); //platform id
-           writeU16(table, 0); //encoding id
-           writeU16(table, 0); //language
-           writeU16(table, codes[t]); //4: full name
+           writeU16(table, 1); //platform id (mac)
+           writeU16(table, 0); //encoding id (latin-1)
+           writeU16(table, 0); //language (english)
+           writeU16(table, codes[t]);
            int len = strlen(strings[t]);
            writeU16(table, len);
            writeU16(table, offset);
            offset += len;
        }
     }
            int len = strlen(strings[t]);
            writeU16(table, len);
            writeU16(table, offset);
            offset += len;
        }
     }
+    for(t=0;t<nr;t++) {
+       if(strings[t]) {
+           writeU16(table, 3); //platform id (windows)
+           writeU16(table, 1); //encoding id (ucs-2)
+           writeU16(table, 0x409); //language (US)
+           writeU16(table, codes[t]);
+           int len2 = strlen(strings[t]) * 2;
+           writeU16(table, len2);
+           writeU16(table, offset);
+           offset += len2;
+       }
+    }
+
     table->data[offset_pos] = table->len>>8;
     table->data[offset_pos+1] = table->len;
 
     table->data[offset_pos] = table->len>>8;
     table->data[offset_pos+1] = table->len;
 
-    for(t=0;t<nr;t++) { 
+    for(t=0;t<nr;t++) {
        if(strings[t]) {
            int len = strlen(strings[t]);
            writeBlock(table, strings[t], len);
        }
     }
        if(strings[t]) {
            int len = strlen(strings[t]);
            writeBlock(table, strings[t], len);
        }
     }
+    for(t=0;t<nr;t++) {
+       if(strings[t]) {
+           int s;
+           int len = strlen(strings[t]);
+           for(s=0;s<len;s++) {
+               writeU8(table, 0);
+               writeU8(table, strings[t][s]);
+           }
+       }
+    }
 }
 void name_delete(ttf_t*ttf)
 {
 }
 void name_delete(ttf_t*ttf)
 {
@@ -1577,6 +1620,14 @@ void name_delete(ttf_t*ttf)
        free(ttf->version_string);
        ttf->version_string=0;
     }
        free(ttf->version_string);
        ttf->version_string=0;
     }
+    if(ttf->font_uid) {
+       free(ttf->font_uid);
+       ttf->font_uid=0;
+    }
+    if(ttf->postscript_name) {
+       free(ttf->postscript_name);
+       ttf->postscript_name=0;
+    }
 }
 
 static table_post_t*post_new(ttf_t*ttf)
 }
 
 static table_post_t*post_new(ttf_t*ttf)
@@ -1587,15 +1638,15 @@ static table_post_t*post_new(ttf_t*ttf)
 void post_parse(memreader_t*r, ttf_t*ttf)
 {
     table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
 void post_parse(memreader_t*r, ttf_t*ttf)
 {
     table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
-    U16 format = readU16(r);
-    post->italic_angle = readU16(r);
+    U32 format = readU32(r);
+    post->italic_angle = readU32(r);
     post->underline_position = readU16(r);
     post->underline_thickness = readU16(r);
     post->underline_position = readU16(r);
     post->underline_thickness = readU16(r);
-    U16 is_monospaced = readU16(r);
-    readU16(r); // min mem 42
-    readU16(r);
-    readU16(r); // min mem 1
-    readU16(r);
+    U16 is_monospaced = readU32(r);
+    readU32(r); // min mem 42
+    readU32(r);
+    readU32(r); // min mem 1
+    readU32(r);
 }
 void post_write(ttf_t*ttf, ttf_table_t*table)
 {
 }
 void post_write(ttf_t*ttf, ttf_table_t*table)
 {
@@ -1618,6 +1669,152 @@ void post_delete(ttf_t*ttf)
     }
 }
 
     }
 }
 
+void cvt_parse(memreader_t*r, ttf_t*ttf)
+{
+    table_cvt_t*cvt = ttf->cvt = rfx_calloc(sizeof(table_cvt_t));
+    cvt->num = r->size/2;
+    cvt->values = malloc(cvt->num*sizeof(S16));
+    int t;
+    for(t=0;t<cvt->num;t++) {
+       cvt->values[t] = readS16(r);
+    }
+}
+void cvt_write(ttf_t*ttf, ttf_table_t*table)
+{
+    table_cvt_t*cvt = ttf->cvt;
+    int t;
+    for(t=0;t<cvt->num;t++) {
+       writeS16(table, cvt->values[t]);
+    }
+}
+void cvt_delete(ttf_t*ttf)
+{
+    if(ttf->cvt) {
+       if(ttf->cvt->values) 
+           free(ttf->cvt->values);
+       free(ttf->cvt);
+       ttf->cvt = 0;
+    }
+}
+
+static table_gasp_t*gasp_new(ttf_t*ttf)
+{
+    table_gasp_t*gasp = rfx_calloc(sizeof(table_gasp_t));
+    gasp->num = 1;
+    gasp->records = rfx_calloc(sizeof(gasp->records[0])*gasp->num);
+
+    gasp->records[0].size = 65535;
+    gasp->records[0].behaviour = 15; //gridfit+grayscale rendering
+    return gasp;
+}
+void gasp_parse(memreader_t*r, ttf_t*ttf)
+{
+    table_gasp_t*gasp = ttf->gasp = rfx_calloc(sizeof(table_gasp_t));
+    readU16(r); //version
+    int num = readU16(r);
+    int t;
+    if(!num) return;
+    gasp->records = malloc(sizeof(gasp->records[0])*num);
+    for(t=0;t<num;t++) {
+       gasp->records[t].size = readU16(r);
+       gasp->records[t].behaviour = readU16(r);
+    }
+}
+
+#define GASP_SYMMETRIC_GRIDFIT 0x0008
+#define GASP_SYMMETRIC_SMOOTHING 0x0004
+#define GASP_DOGRAY 0x0002
+#define GASP_GRIDFIT 0x0001
+
+void gasp_write(ttf_t*ttf, ttf_table_t*table)
+{
+    table_gasp_t*gasp = ttf->gasp;
+    int version = 0;
+    int t;
+    for(t=0;t<gasp->num;t++) {
+       if(gasp->records[t].behaviour & ~(GASP_GRIDFIT | GASP_DOGRAY)) {
+           version = 1;
+       }
+    }
+    writeU16(table, version);
+    writeU16(table, gasp->num);
+    for(t=0;t<gasp->num;t++) {
+       writeU16(table, gasp->records[t].size);
+       writeU16(table, gasp->records[t].behaviour);
+    }
+}
+void gasp_delete(ttf_t*ttf)
+{
+    if(ttf->gasp) {
+       if(ttf->gasp->records)
+           free(ttf->gasp->records);
+       free(ttf->gasp);
+       ttf->gasp = 0;
+    }
+}
+
+table_code_t*prep_new(ttf_t*ttf)
+{
+    table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
+    ttf_table_t*t = ttf_table_new(0);
+    writeU8(t,0xb8);writeU16(t,0x1ff); // pushword(0x1ff)
+    writeU8(t,0x85); //scanctrl (always do dropout, for all sizes)
+    writeU8(t,0xb0);writeU8(t,1); // pushbyte(1)
+    writeU8(t,0x8d); //scantype (simple dropout control w/o stubs)
+    writeU8(t,0xb0);writeU8(t,5); // pushbyte(5)
+    writeU8(t,0x8d); //scantype (for windows) smart dropout control w/o stubs
+    prep->code = t->data;
+    prep->size = t->len;
+    free(t);
+    return prep;
+
+}
+void fpgm_parse(memreader_t*r, ttf_t*ttf)
+{
+    table_code_t*fpgm = ttf->fpgm  = rfx_calloc(sizeof(table_code_t));
+    if(!r->size) return;
+    fpgm->size = r->size;
+    fpgm->code = malloc(r->size);
+    readBlock(r, fpgm->code, r->size);
+}
+void fpgm_write(ttf_t*ttf, ttf_table_t*table)
+{
+    table_code_t*code = ttf->fpgm;
+    writeBlock(table, code->code, code->size);
+}
+void fpgm_delete(ttf_t*ttf)
+{
+    if(ttf->fpgm) {
+       if(ttf->fpgm->code)
+           free(ttf->fpgm->code);
+       free(ttf->fpgm);
+       ttf->fpgm = 0;
+    }
+}
+
+void prep_parse(memreader_t*r, ttf_t*ttf)
+{
+    table_code_t*prep = ttf->prep  = rfx_calloc(sizeof(table_code_t));
+    if(!r->size) return;
+    prep->size = r->size;
+    prep->code = malloc(r->size);
+    readBlock(r, prep->code, r->size);
+}
+void prep_write(ttf_t*ttf, ttf_table_t*table)
+{
+    table_code_t*code = ttf->prep;
+    writeBlock(table, code->code, code->size);
+}
+void prep_delete(ttf_t*ttf)
+{
+    if(ttf->prep) {
+       if(ttf->prep->code)
+           free(ttf->prep->code);
+       free(ttf->prep);
+       ttf->prep = 0;
+    }
+}
+
 static int ttf_parse_tables(ttf_t*ttf)
 {
     ttf_table_t*table;
 static int ttf_parse_tables(ttf_t*ttf)
 {
     ttf_table_t*table;
@@ -1630,7 +1827,7 @@ static int ttf_parse_tables(ttf_t*ttf)
     INIT_READ(m, table->data, table->len, 0);
     int loc_index = head_parse(ttf, &m);
     ttf_table_delete(ttf, table);
     INIT_READ(m, table->data, table->len, 0);
     int loc_index = head_parse(ttf, &m);
     ttf_table_delete(ttf, table);
-    
+
     table = ttf_find_table(ttf, TAG_MAXP);
     if(!table) {
        msg("<error> Font has no maxp table");
     table = ttf_find_table(ttf, TAG_MAXP);
     if(!table) {
        msg("<error> Font has no maxp table");
@@ -1639,7 +1836,7 @@ static int ttf_parse_tables(ttf_t*ttf)
     INIT_READ(m2, table->data, table->len, 0);
     ttf->maxp = maxp_parse(ttf, &m2);
     ttf_table_delete(ttf, table);
     INIT_READ(m2, table->data, table->len, 0);
     ttf->maxp = maxp_parse(ttf, &m2);
     ttf_table_delete(ttf, table);
-    
+
     if(!ttf->num_glyphs) {
        msg("<error> Invalid number of characters");
        return 0;
     if(!ttf->num_glyphs) {
        msg("<error> Invalid number of characters");
        return 0;
@@ -1653,12 +1850,13 @@ static int ttf_parse_tables(ttf_t*ttf)
         ttf_table_delete(ttf, table);
     }
 
         ttf_table_delete(ttf, table);
     }
 
+
     table = ttf_find_table(ttf, TAG_HHEA);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
        int num_advances = hea_parse(&m, ttf);
         ttf_table_delete(ttf, table);
     table = ttf_find_table(ttf, TAG_HHEA);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
        int num_advances = hea_parse(&m, ttf);
         ttf_table_delete(ttf, table);
-       
+
        table = ttf_find_table(ttf, TAG_HMTX);
        if(table) {
            INIT_READ(m, table->data, table->len, 0);
        table = ttf_find_table(ttf, TAG_HMTX);
        if(table) {
            INIT_READ(m, table->data, table->len, 0);
@@ -1696,14 +1894,21 @@ static int ttf_parse_tables(ttf_t*ttf)
        }
        free(loca);
     }
        }
        free(loca);
     }
-    
+
     table = ttf_find_table(ttf, TAG_CMAP);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
        cmap_parse(&m, ttf);
        ttf_table_delete(ttf, table);
     }
     table = ttf_find_table(ttf, TAG_CMAP);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
        cmap_parse(&m, ttf);
        ttf_table_delete(ttf, table);
     }
-    
+
+    table = ttf_find_table(ttf, TAG_POST);
+    if(table) {
+       INIT_READ(m, table->data, table->len, 0);
+       post_parse(&m, ttf);
+       ttf_table_delete(ttf, table);
+    }
+
     table = ttf_find_table(ttf, TAG_NAME);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
     table = ttf_find_table(ttf, TAG_NAME);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
@@ -1711,10 +1916,31 @@ static int ttf_parse_tables(ttf_t*ttf)
        ttf_table_delete(ttf, table);
     }
 
        ttf_table_delete(ttf, table);
     }
 
-    table = ttf_find_table(ttf, TAG_POST);
+    table = ttf_find_table(ttf, TAG_CVT);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
     if(table) {
        INIT_READ(m, table->data, table->len, 0);
-       post_parse(&m, ttf);
+       cvt_parse(&m, ttf);
+       ttf_table_delete(ttf, table);
+    }
+    
+    table = ttf_find_table(ttf, TAG_GASP);
+    if(table) {
+       INIT_READ(m, table->data, table->len, 0);
+       gasp_parse(&m, ttf);
+       ttf_table_delete(ttf, table);
+    }
+    
+    table = ttf_find_table(ttf, TAG_PREP);
+    if(table) {
+       INIT_READ(m, table->data, table->len, 0);
+       prep_parse(&m, ttf);
+       ttf_table_delete(ttf, table);
+    }
+    
+    table = ttf_find_table(ttf, TAG_FPGM);
+    if(table) {
+       INIT_READ(m, table->data, table->len, 0);
+       fpgm_parse(&m, ttf);
        ttf_table_delete(ttf, table);
     }
 
        ttf_table_delete(ttf, table);
     }
 
@@ -1723,11 +1949,11 @@ static int ttf_parse_tables(ttf_t*ttf)
 static void ttf_collapse_tables(ttf_t*ttf)
 {
     ttf_table_t*table;
 static void ttf_collapse_tables(ttf_t*ttf)
 {
     ttf_table_t*table;
-    
+
     ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
     ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
-    if(head) 
+    if(head)
        return; //already collapsed
        return; //already collapsed
-  
+
     if(ttf->maxp) {
        table = ttf_addtable(ttf, TAG_MAXP);
        maxp_write(ttf, table);
     if(ttf->maxp) {
        table = ttf_addtable(ttf, TAG_MAXP);
        maxp_write(ttf, table);
@@ -1755,7 +1981,7 @@ static void ttf_collapse_tables(ttf_t*ttf)
            hea_delete(ttf);
        }
     }
            hea_delete(ttf);
        }
     }
-       
+
     int loca_size=0;
     if(ttf->num_glyphs) {
        if(ttf->unicode) {
     int loca_size=0;
     if(ttf->num_glyphs) {
        if(ttf->unicode) {
@@ -1774,7 +2000,7 @@ static void ttf_collapse_tables(ttf_t*ttf)
        }
     }
 
        }
     }
 
-    if(ttf->full_name || ttf->family_name || ttf->subfamily_name) {
+    if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) {
        table = ttf_addtable(ttf, TAG_NAME);
        name_write(ttf, table);
        name_delete(ttf);
        table = ttf_addtable(ttf, TAG_NAME);
        name_write(ttf, table);
        name_delete(ttf);
@@ -1784,7 +2010,27 @@ static void ttf_collapse_tables(ttf_t*ttf)
        post_write(ttf, table);
        post_delete(ttf);
     }
        post_write(ttf, table);
        post_delete(ttf);
     }
-    
+    if(ttf->cvt) {
+       table = ttf_addtable(ttf, TAG_CVT);
+       cvt_write(ttf, table);
+       cvt_delete(ttf);
+    }
+    if(ttf->gasp) {
+       table = ttf_addtable(ttf, TAG_GASP);
+       gasp_write(ttf, table);
+       gasp_delete(ttf);
+    }
+    if(ttf->fpgm) {
+       table = ttf_addtable(ttf, TAG_FPGM);
+       fpgm_write(ttf, table);
+       fpgm_delete(ttf);
+    }
+    if(ttf->prep) {
+       table = ttf_addtable(ttf, TAG_PREP);
+       prep_write(ttf, table);
+       prep_delete(ttf);
+    }
+
     table = ttf_addtable(ttf, TAG_HEAD);
     head_write(ttf, table, loca_size);
     head_delete(ttf);
     table = ttf_addtable(ttf, TAG_HEAD);
     head_write(ttf, table, loca_size);
     head_delete(ttf);
@@ -1811,7 +2057,7 @@ ttf_t* ttf_load(void*data, int length)
        U32 fontDataSize = readU32(&r);
        U32 version = readU32(&r);
        U32 flags  = readU32(&r);
        U32 fontDataSize = readU32(&r);
        U32 version = readU32(&r);
        U32 flags  = readU32(&r);
-       U8 panose[10]; 
+       U8 panose[10];
        readBlock(&r, panose, 10);
        readU8(&r); //charset
        readU8(&r); //italoc
        readBlock(&r, panose, 10);
        readU8(&r); //charset
        readU8(&r); //italoc
@@ -1880,17 +2126,17 @@ ttf_t* ttf_load(void*data, int length)
        r.pos = font1_position;
        ttf->version = readU32(&r);
     }
        r.pos = font1_position;
        ttf->version = readU32(&r);
     }
-    
+
     int num_tables = readU16(&r);
     int num_tables = readU16(&r);
-    
+
     readU16(&r); //search range
     readU16(&r); //entry selector
     readU16(&r); //range shift
 
     if(num_tables*16 > length) {
        msg("<error> Truncated TTF file (table entries: %d)", num_tables);
     readU16(&r); //search range
     readU16(&r); //entry selector
     readU16(&r); //range shift
 
     if(num_tables*16 > length) {
        msg("<error> Truncated TTF file (table entries: %d)", num_tables);
-       if(ttf->version != OPENTYPE && 
-          ttf->version != TRUETYPE_MACOS && 
+       if(ttf->version != OPENTYPE &&
+          ttf->version != TRUETYPE_MACOS &&
           ttf->version != VERSION_1_0) {
            // bad table length, weird version. This is probably not a ttf file.
            return 0;
           ttf->version != VERSION_1_0) {
            // bad table length, weird version. This is probably not a ttf file.
            return 0;
@@ -1907,21 +2153,21 @@ ttf_t* ttf_load(void*data, int length)
        U32 checksum = table_data[t*4+1];
        U32 pos = table_data[t*4+2];
        U32 len = table_data[t*4+3];
        U32 checksum = table_data[t*4+1];
        U32 pos = table_data[t*4+2];
        U32 len = table_data[t*4+3];
-
+       
        if(pos+len > length) {
            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);
        } else {
            U8*mem = malloc(len);
            r.pos = pos;
            readBlock(&r, mem, len);
        if(pos+len > length) {
            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);
        } else {
            U8*mem = malloc(len);
            r.pos = pos;
            readBlock(&r, mem, len);
-           
+
            ttf_table_t*table = ttf_addtable(ttf, tag);
            table->data = mem;
            table->len = table->memsize = len;
 #if 0
            U32 checksum2 = ttf_table_checksum(table);
            if(checksum2!=checksum) {
            ttf_table_t*table = ttf_addtable(ttf, tag);
            table->data = mem;
            table->len = table->memsize = len;
 #if 0
            U32 checksum2 = ttf_table_checksum(table);
            if(checksum2!=checksum) {
-               msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
+               msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
                        (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                        (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                        len, checksum2, checksum);
                        (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                        (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                        len, checksum2, checksum);
@@ -1931,16 +2177,16 @@ ttf_t* ttf_load(void*data, int length)
     }
     free(table_data);
 
     }
     free(table_data);
 
-    if(!ttf_parse_tables(ttf)) 
+    if(!ttf_parse_tables(ttf))
        return 0;
 
     return ttf;
 }
 void ttf_create_truetype_tables(ttf_t*ttf)
 {
        return 0;
 
     return ttf;
 }
 void ttf_create_truetype_tables(ttf_t*ttf)
 {
-    if(!ttf->head) 
+    if(!ttf->head)
        ttf->head = head_new(ttf);
        ttf->head = head_new(ttf);
-    if(!ttf->maxp) 
+    if(!ttf->maxp)
        ttf->maxp = maxp_new(ttf);
     if(!ttf->hea)
        ttf->hea = hea_new(ttf);
        ttf->maxp = maxp_new(ttf);
     if(!ttf->hea)
        ttf->hea = hea_new(ttf);
@@ -1948,12 +2194,16 @@ void ttf_create_truetype_tables(ttf_t*ttf)
        ttf->os2 = os2_new(ttf);
     if(!ttf->post)
        ttf->post = post_new(ttf);
        ttf->os2 = os2_new(ttf);
     if(!ttf->post)
        ttf->post = post_new(ttf);
+    if(!ttf->gasp)
+       ttf->gasp = gasp_new(ttf);
+    if(!ttf->prep)
+       ttf->prep = prep_new(ttf);
 }
 
 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
 {
     ttf_collapse_tables(ttf);
 }
 
 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
 {
     ttf_collapse_tables(ttf);
-   
+
     ttf_table_t*file = ttf_table_new(0);
     writeU32(file, VERSION_1_0);
 
     ttf_table_t*file = ttf_table_new(0);
     writeU32(file, VERSION_1_0);
 
@@ -1965,7 +2215,7 @@ ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
        t = t->next;
     }
     writeU16(file, num_tables);
        t = t->next;
     }
     writeU16(file, num_tables);
-    
+
     /* write search range */
     int tmp = num_tables;
     int search_range = 0;
     /* write search range */
     int tmp = num_tables;
     int search_range = 0;
@@ -2056,42 +2306,24 @@ ttf_table_t* ttf_eot_head(ttf_t*ttf)
     writeU32(file, 0); //reserved[3]
     writeU16(file, 0); //padding(1)
 
     writeU32(file, 0); //reserved[3]
     writeU16(file, 0); //padding(1)
 
-    int t,len;
+    int i,t,len;
 
 
-    //family name
-    len = strlen(ttf->family_name);
-    writeU16_LE(file, len*2);
-    for(t=0;t<len;t++) {
-       writeU8(file, 0);
-       writeU8(file, ttf->family_name[t]);
-    }
-    writeU16(file, 0); //zero byte pad
+    char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
+    int nr = sizeof(strings)/sizeof(strings[0]);
 
 
-    //subfamily name
-    len = strlen(ttf->subfamily_name);
-    writeU16_LE(file, len*2);
-    for(t=0;t<len;t++) {
-       writeU8(file, 0);
-       writeU8(file, ttf->subfamily_name[t]);
-    }
-    writeU16(file, 0); //zero byte pad
+    for(i=0;i<nr;i++) {
+       char *string = strings[i];
 
 
-    //version string
-    len = strlen(ttf->version_string);
-    writeU16_LE(file, len*2); //len
-    for(t=0;t<len;t++) {
-       writeU8(file, 0);
-       writeU8(file, ttf->version_string[t]);
+       //family name
+       len = strlen(string);
+       writeU16_LE(file, len*2);
+       for(t=0;t<len;t++) {
+           writeU8(file, 0);
+           writeU8(file, string[t]);
+       }
+       writeU16(file, 0); //zero byte pad
     }
     }
-    writeU16(file, 0); //zero byte pad
 
 
-    //full name
-    len = strlen(ttf->full_name);
-    writeU16_LE(file, len*2); //len
-    for(t=0;t<len;t++) {
-       writeU8(file, 0);
-       writeU8(file, ttf->full_name[t]);
-    }
     writeU16(file, 0); //zero byte pad
 
     writeU16(file, 0); //padding(2)
     writeU16(file, 0); //zero byte pad
 
     writeU16(file, 0); //padding(2)
@@ -2110,7 +2342,7 @@ void ttf_save_eot(ttf_t*ttf, const char*filename)
     len_data[1] = full_len>>8;
     len_data[2] = full_len>>16;
     len_data[3] = full_len>>24;
     len_data[1] = full_len>>8;
     len_data[2] = full_len>>16;
     len_data[3] = full_len>>24;
-    
+
     U8*len_data2 = eot->data+4;
     len_data2[0] = t->len>>0;
     len_data2[1] = t->len>>8;
     U8*len_data2 = eot->data+4;
     len_data2[0] = t->len>>0;
     len_data2[1] = t->len>>8;
@@ -2155,8 +2387,8 @@ void ttf_dump(ttf_t*ttf)
     ttf_table_t*table = ttf->tables;
     while(table) {
        U32 tag = table->id;
     ttf_table_t*table = ttf->tables;
     while(table) {
        U32 tag = table->id;
-       msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", 
-               (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, 
+       msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
+               (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
        table = table->next;
     }
                (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
        table = table->next;
     }
@@ -2192,6 +2424,7 @@ void ttf_destroy(ttf_t*ttf)
     hea_delete(ttf);
     glyf_delete(ttf);
     post_delete(ttf);
     hea_delete(ttf);
     glyf_delete(ttf);
     post_delete(ttf);
+    cvt_delete(ttf);
     name_delete(ttf);
     free(ttf);
 }
     name_delete(ttf);
     free(ttf);
 }
@@ -2201,26 +2434,24 @@ int main(int argn, const char*argv[])
 {
     setConsoleLogging(7);
     const char*filename = "comic.ttf";
 {
     setConsoleLogging(7);
     const char*filename = "comic.ttf";
-    if(argn>1) 
+    if(argn>1)
        filename = argv[1];
     //msg("<notice> Loading %s", filename);
     memfile_t*m = memfile_open(filename);
     ttf_t*ttf = ttf_load(m->data, m->len);
        filename = argv[1];
     //msg("<notice> Loading %s", filename);
     memfile_t*m = memfile_open(filename);
     ttf_t*ttf = ttf_load(m->data, m->len);
+
     if(!ttf) {
        msg("<error> Couldn't load %s", filename);
        return 1;
     }
     ttf_reduce(ttf);
     if(!ttf) {
        msg("<error> Couldn't load %s", filename);
        return 1;
     }
     ttf_reduce(ttf);
-    
-    ttf->full_name = strdup("Test-Normal");
-    ttf->family_name = strdup("Test");
-    ttf->subfamily_name = strdup("Normal");
-    ttf->version_string = strdup("Version 1.0");
+
+    ttf_create_truetype_tables(ttf);
 
     if(!ttf) return 1;
     memfile_close(m);
     //ttf_dump(ttf);
 
     if(!ttf) return 1;
     memfile_close(m);
     //ttf_dump(ttf);
-    //printf("os2 version: %04x (%d), maxp size: %d\n", 
+    //printf("os2 version: %04x (%d), maxp size: %d\n",
 //         ttf->os2->version, ttf->os2->size, ttf->maxp->size);
     ttf_save_eot(ttf, "testfont.eot");
     ttf_save(ttf, "testfont.ttf");
 //         ttf->os2->version, ttf->os2->size, ttf->maxp->size);
     ttf_save_eot(ttf, "testfont.eot");
     ttf_save(ttf, "testfont.ttf");