I'm doing a brain dump for posterity on this task; you can tune out
of this email; it's mostly meant for Google archiving purposes.

I've spent far more time than I should on this implementation;
I originally did a quick + dirty version that was not binary
compatible with Windows .fot files.  Worked like a charm; I could
run Civ III (yay!).

But Alexandre said, gee, it should be easy to make it create a binary
compatible .fot file, take an afternoon and do that, why don't you, Jer?
Several weeks and a lot of swearing later, I now know far more about the
format of .fot files and fontdir resource structures than I care to.

I'm attaching a program that was useful to me; it dumped many chunks
of info about a .ttf file from FreeType.  Comparing that to a .fot file
generated on Windows was helpful.  I'm also attaching a hex dump of a .fot
file with my annotation on the basic structure.

The hard parts were that the .fot format seems to be an NE image, but
it seems to have subtle bugs in it and that the FONTDIR resource structure
is not well documented.  I've mostly sussed out how to use Freetype
to replicate most of the members; there are still a few I don't have
quite right.  (And I probably get this all wrong in non US or double
byte locales.  :-/)

The previous patches contain essentially all of my hard won knowledge
of the FONTDIR structure.

Cheers,

Jeremy
#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#ifdef HAVE_FREETYPE

#ifdef HAVE_FT2BUILD_H
#include <ft2build.h>
#endif
#include FT_FREETYPE_H
#include FT_SFNT_NAMES_H
#include FT_TRUETYPE_TABLES_H
#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_IDS_H
#ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
#include <freetype/internal/sfnt.h>
#endif

#include "wine/unicode.h"
#include "wine/wingdi16.h"
#include "wingdi.h"


static void usage(char **argv)
{
    fprintf(stderr, "%s foo.ttf\n", argv[0]);
    return;
}



static int dump_ttf(char *filename)
{
    TT_OS2 *os2;
    TT_Header *header;
    TT_HoriHeader *hheader;
    char glyph_name[256];
    int i;

    FT_Face face;
    FT_Library lib;

    if(FT_Init_FreeType(&lib))
        return -1;

    if(FT_New_Face(lib, filename, 0, &face)) {
        fprintf(stderr, "Can't open face %s\n", filename);
        return(-2);
    }

    os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
    header = FT_Get_Sfnt_Table(face, ft_sfnt_head);
    hheader = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);

    strcpy(glyph_name, "N/A");
    for (i = 0; i < face->num_glyphs; i++)
    {
        if (FT_Get_Glyph_Name(face, i, glyph_name, sizeof(glyph_name)) == 0)
            break;
    }

    for (i = 0; i < FT_Get_Sfnt_Name_Count(face); i++)
    {
        FT_SfntName name;

        if (FT_Get_Sfnt_Name(face, i, &name) == 0)
            printf("Sfnt_Name %d: [platform %d|encoding %d|language %d|name_id %d|string %*.*s]\n", 
              i, name.platform_id, name.encoding_id, name.language_id, name.name_id, name.string_len, name.string_len, name.string);
    }

    printf("num_faces 0x%lx\n", face->num_faces);
    printf("face_index 0x%lx\n", face->face_index);
    printf("face_flags 0x%lx\n", face->face_flags);
    printf("style_flags 0x%lx\n", face->style_flags);
    printf("num_glyphs 0x%lx\n", face->num_glyphs);
    printf("family_name [%s]\n", face->family_name);
    printf("style_name [%s]\n", face->style_name);
    printf("FT_Get_Postscript_Name [%s]\n", FT_Get_Postscript_Name(face));
    printf("glyph_name [%s]\n", glyph_name);
    printf("num_fixed_sizes 0x%x\n", face->num_fixed_sizes);
    printf("num_charmaps 0x%x\n", face->num_charmaps);

    printf("BBox: [xMin 0x%lx|yMin 0x%lx|xMax 0x%lx|yMax 0x%lx]\n", 
            face->bbox.xMin, face->bbox.yMin, face->bbox.xMax, face->bbox.yMax);
    printf("units_per_EM 0x%x\n", face->units_per_EM);
    printf("ascender 0x%hx\n", face->ascender);
    printf("descender 0x%hx\n", face->descender);
    printf("height 0x%hx\n", face->height);
    printf("max_advance_width 0x%hx\n", face->max_advance_width);
    printf("max_advance_height 0x%hx\n", face->max_advance_height);
    printf("underline_position 0x%hx\n", face->underline_position);
    printf("underline_thickness 0x%hx\n", face->underline_thickness);

    printf("glyph metrics [width 0x%lx|height 0x%lx|horiBearingX 0x%lx|horiBearyingY 0x%lx|horiAdvance 0x%lx|vertBearingX 0x%lx|vertBearyingY 0x%lx|vertAdvance 0x%lx]\n",
            face->glyph->metrics.width, 
            face->glyph->metrics.height, 
            face->glyph->metrics.horiBearingX, 
            face->glyph->metrics.horiBearingY, 
            face->glyph->metrics.horiAdvance, 
            face->glyph->metrics.vertBearingX, 
            face->glyph->metrics.vertBearingY, 
            face->glyph->metrics.vertAdvance);
    printf("glyph linearHoriAdvance 0x%lx\n", face->glyph->linearHoriAdvance);
    printf("glyph linearVertAdvance 0x%lx\n", face->glyph->linearVertAdvance);
    printf("glyph format 0x%x\n", face->glyph->format);

    if (header)
    {
        printf("header->Flags 0x%x\n", header->Flags);
        printf("header->xMin 0x%x\n", header->xMin);
        printf("header->yMin 0x%x\n", header->yMin);
        printf("header->xMax 0x%x\n", header->xMax);
        printf("header->yMax 0x%x\n", header->yMax);
    }

    if (hheader)
    {
        printf("hheader->xMax_Extent 0x%x\n", hheader->xMax_Extent);
        printf("hheader->min_Left_Side_Bearing 0x%x\n", hheader->min_Left_Side_Bearing);
        printf("hheader->min_Right_Side_Bearing 0x%x\n", hheader->min_Right_Side_Bearing);
        printf("hheader->advance_Width_Max 0x%x\n", hheader->advance_Width_Max);
    }

    if (os2)
    {
        printf("os2->version 0x%x\n", os2->version);
        printf("os2->xAvgCharWidth 0x%x\n", os2->xAvgCharWidth);
        printf("os2->usWidthClass 0x%x\n", os2->usWidthClass);
        printf("os2->usWeightClass 0x%x\n", os2->usWeightClass);
        printf("os2->usWinAscent 0x%x\n", os2->usWinAscent);
        printf("os2->usWinDescent 0x%x\n", os2->usWinDescent);
        printf("os2->usFirstCharIndex 0x%x\n", os2->usFirstCharIndex);
        printf("os2->usLastCharIndex 0x%x\n", os2->usLastCharIndex);
        printf("os2->fsType 0x%x\n", os2->fsType);
        printf("os2->panose[PAN_FAMILYTYPE_INDEX] 0x%x\n", os2->panose[PAN_FAMILYTYPE_INDEX]);
        printf("os2->panose[PAN_SERIFSTYLE_INDEX] 0x%x\n", os2->panose[PAN_SERIFSTYLE_INDEX]);
        printf("os2->panose[PAN_WEIGTH_INDEX] 0x%x\n", os2->panose[PAN_WEIGTH_INDEX]);
        printf("os2->panose[PAN_PROPORTION_INDEX] 0x%x\n", os2->panose[PAN_PROPORTION_INDEX]);
        printf("os2->panose[PAN_CONTRAST_INDEX] 0x%x\n", os2->panose[PAN_CONTRAST_INDEX]);
        printf("os2->panose[PAN_STROKEVARIATION_INDEX] 0x%x\n", os2->panose[PAN_STROKEVARIATION_INDEX]);
        printf("os2->panose[PAN_ARMSTYLE_INDEX] 0x%x\n", os2->panose[PAN_ARMSTYLE_INDEX]);
        printf("os2->panose[PAN_LETTERFORM_INDEX] 0x%x\n", os2->panose[PAN_LETTERFORM_INDEX]);
        printf("os2->panose[PAN_MIDLINE_INDEX] 0x%x\n", os2->panose[PAN_MIDLINE_INDEX]);
        printf("os2->panose[PAN_XHEIGHT_INDEX] 0x%x\n", os2->panose[PAN_XHEIGHT_INDEX]);
        printf("os2->fsTypoAscender 0x%x\n", os2->sTypoAscender);
        printf("os2->fsTypoDescender 0x%x\n", os2->sTypoDescender);
        printf("os2->fsTypoLineGap 0x%x\n", os2->sTypoLineGap);
        printf("os2->fsSelection 0x%x\n", os2->fsSelection);
        printf("os2->sxHeight 0x%x\n", os2->sxHeight);
        printf("os2->sCapHeight 0x%x\n", os2->sCapHeight);
        printf("os2->sFamilyClass 0x%x\n", os2->sFamilyClass);
        printf("os2->usDefaultChar 0x%x\n", os2->usDefaultChar);
        printf("os2->usBreakChar 0x%x\n", os2->usBreakChar);


    }

    return 0;
}


int main(int argc, char **argv)
{
    int rc;

    if(argc != 2) {
        usage(argv);
        return (-1);
    }

    dump_ttf(argv[1]);

    return rc;

}

#else /* HAVE_FREETYPE */

int main(int argc, char **argv)
{
    fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
    exit(1);
}

#endif /* HAVE_FREETYPE */
Annotated hex dump of lucon.fot, a file created on Windows with 
CreateScalableFontResource
against lucon.ttf.  Useful for determining the structure of .fot files.

DOS
00000000  4d 5a 01 00 02 00 00 00  04 00 0f 00 ff ff 00 00  |MZ..............|
00000010  b8 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  |[EMAIL PROTECTED]|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 80 00 00 00  |................|
00000040  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050  69 73 20 69 73 20 61 20  54 72 75 65 54 79 70 65  |is is a TrueType|
00000060  20 66 6f 6e 74 2c 20 6e  6f 74 20 61 20 70 72 6f  | font, not a pro|
00000070  67 72 61 6d 2e 0d 0d 0a  24 00 4b 69 65 73 61 00  |gram....$.Kiesa.|

NE
00000080  4e 45 05 10 8a 00 02 00  00 00 00 00 00 80 00 00  |NE..............|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000a0  1a 00 40 00 40 00 74 00  7f 00 7f 00 0e 01 00 00  |[EMAIL 
PROTECTED]@.t.........|
000000b0  00 00 04 00 02 00 02 00  00 00 00 00 00 00 00 03  |................|


START RESOURCE TABLE
Shift 
000000c0  04 00 

Type + Name 0
                07 80 01 00 00 00  00 00 48 00 0a 00 50 0c  |..........H...P.|
000000d0  2c 00 00 00 00 00 


Type + Name 1
                            cc 80  01 00 00 00 00 00 40 00  |,[EMAIL PROTECTED]|
000000e0  08 00 50 0c 01 80 00 00  00 00 


Flag to end all types + names
                                         00 00 
                                               07 46 4f 4e  |..P..........FON|
000000f0  54 44 49 52 05 4c 55 43  4f 4e 00                 |TDIR.LUCON.     |
END RESOURCE TABLE

                      ^^^

   This is odd.  That's fairly clearly the last string in the name/type string
part of the resource table.  Further, just a little further along, we
have a clear place where the resident name table should start.  But the header
says it starts at 0x74 relative, which is right there.  And the clear place
for it to start is at 0x7f.  


Mystery bytes:  (0xf9, 0x79 relative)
                                            00 00 00 00 

Apparent resident name table: (0xff, 0x7f relative)
                                                        0a  |               .|
00000100  4c 55 43 4f 4e 2e 54 54  46 00                    |LUCON.TTF.      |

Apparent module reference table: (0x10a, 0x8a relative)
                                        00 00 00 00 

Non resident name table: (0x10e)
                                                     1a 46  |              .F|
00000110  4f 4e 54 52 45 53 3a 4c  75 63 69 64 61 20 43 6f  |ONTRES:Lucida Co|
00000120  6e 73 6f 6c 65 00 00 00  00 00 00 00 00 00 00 00  |nsole...........|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000200  c3 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

         ^^^

        What the hell!?!?!

00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000220  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000230  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000240  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000250  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000260  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000270  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000280  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000290  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000300  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000310  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000320  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000330  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000340  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000350  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000360  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000370  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000380  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000390  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000400  43 3a 5c 57 49 4e 44 4f  57 53 5c 66 6f 6e 74 73  |C:\WINDOWS\fonts|
00000410  5c 4c 55 43 4f 4e 2e 54  54 46 00 00 00 00 00 00  |\LUCON.TTF......|
00000420  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000430  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000440  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000450  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000460  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000470  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000480  01 00 00 00 00 02 95 00  00 00 57 69 6e 64 6f 77  |..........Window|
00000490  73 21 20 57 69 6e 64 6f  77 73 21 20 57 69 6e 64  |s! Windows! Wind|
000004a0  6f 77 73 21 00 10 03 01  01 00 00 00 00 00 00 00  |ows!............|
000004b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000004c0  00 00 00 00 00 00 03 40  00 08 48 00 48 00 50 06  |[EMAIL PROTECTED]|
000004d0  00 00 00 00 00 00 00 90  01 00 00 00 00 08 36 d2  |..............6.|
000004e0  04 d2 04 1e ff 01 02 00  00 00 00 00 00 76 00 00  |.............v..|
000004f0  00 0c 00 00 00 ff 4c 75  63 69 64 61 20 43 6f 6e  |......Lucida Con|
00000500  73 6f 6c 65 00 4c 75 63  69 64 61 20 43 6f 6e 73  |sole.Lucida Cons|
00000510  6f 6c 65 00 52 65 67 75  6c 61 72 00 00 00 00 00  |ole.Regular.....|
00000520  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000530  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000540  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000550  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000560  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000570  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000580  00                                                |.|
00000581


Reply via email to