テーブル一覧を読み込み

テーブル一覧を読み込むプログラム
では、実際にここまでの情報を読み込んで、フォントのテーブル一覧を表示してみます。

引数でフォントファイル (複数可) を指定すると、テーブルの情報を表示します。

03_tables.c
/*******************************
 * テーブル一覧表示
 *
 * [usage] exe <files>
 *******************************/

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


/* 2byte 読み込み */

uint16_t read16(FILE *fp)
{
    uint8_t b[2];

    fread(b, 1, 2, fp);

    return (b[0] << 8) | b[1];
}

/* 4byte 読み込み */

uint32_t read32(FILE *fp)
{
    uint8_t b[4];

    fread(b, 1, 4, fp);

    return ((uint32_t)b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
}

/* Tag を表示 */

void put_tag(uint32_t t)
{
    printf("'%c%c%c%c' (0x%08X)",
        t >> 24, (t >> 16) & 255, (t >> 8) & 255, t & 255,
        t);
}

/* オフセットテーブル */

void read_offset_table(FILE *fp)
{
    uint32_t ver,name,cksum,offset,len;
    uint16_t num,srange,esel,rshi;

    //バージョン
    ver = read32(fp);
    //テーブル数
    num = read16(fp);
    //searchRange
    srange = read16(fp);
    //entrySelector
    esel = read16(fp);
    //rangeShift
    rshi = read16(fp);

    printf("\n==== offset table ====\n");
    printf("version: 0x%08X | numTables: %d\n", ver, num);
    printf("searchRange: %d | entrySelector: %d | rangeShift: %d\n\n",
        srange, esel, rshi);

    printf(" tag                | checksum   | offset     | len\n");
    printf("-----------------------------------------------------------\n");

    //TableRecord

    for(; num > 0; num--)
    {
        //識別子
        name = read32(fp);
        //チェックサム
        cksum = read32(fp);
        //オフセット位置
        offset = read32(fp);
        //長さ
        len = read32(fp);

        put_tag(name);
        printf(" | 0x%08X | 0x%08X | %u\n", cksum, offset, len);
    }
}

/* TTC ヘッダ */

void read_ttc_header(FILE *fp)
{
    uint32_t i,htag,num,dsig_tag,dsig_len,dsig_offset;
    uint32_t *pfont_offset;
    uint16_t majver,minver;

    //ヘッダ
    htag = read32(fp);
    //メジャーバージョン
    majver = read16(fp);
    //マイナーバージョン
    minver = read16(fp);
    //フォント数
    num = read32(fp);

    printf("\n---- TTC header ----\n");
    printf("tag:");
    put_tag(htag);
    printf(" | version: %d.%d | font nums: %u\n",
        majver, minver, num);

    //各フォントのオフセット位置

    pfont_offset = (uint32_t *)malloc(4 * num);
    if(!pfont_offset) return;

    for(i = 0; i < num; i++)
        pfont_offset[i] = read32(fp);

    //ver 2.0

    if(majver == 2 && minver == 0)
    {
        //タグ
        dsig_tag = read32(fp);
        //長さ
        dsig_len = read32(fp);
        //オフセット
        dsig_offset = read32(fp);

        printf("[DSIG] tag:");
        put_tag(dsig_tag);
        printf(" | len: %u | offset: %u\n", dsig_len, dsig_offset);
    }

    //各フォント

    for(i = 0; i < num; i++)
    {
        fseek(fp, pfont_offset[i], SEEK_SET);

        read_offset_table(fp);
    }

    free(pfont_offset);
}

/* ファイル読み込み */

void read_file(char *filename)
{
    FILE *fp;
    uint32_t ver;

    printf("\n<<<< %s >>>>\n", filename);

    fp = fopen(filename, "rb");
    if(!fp)
    {
        printf("can't open '%s'\n", filename);
        return;
    }

    //先頭4byteで判定

    ver = read32(fp);
    rewind(fp);

    if(ver == 0x74746366)
        read_ttc_header(fp);
    else
        read_offset_table(fp);

    fclose(fp);
}

/* main */

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

    for(i = 1; i < argc; i++)
        read_file(argv[i]);
    
    return 0;
}
OTF ファイルの場合
==== offset table ====
version: 0x4F54544F | numTables: 17
searchRange: 256 | entrySelector: 4 | rangeShift: 16

 tag                | checksum   | offset     | len
-----------------------------------------------------------
'BASE' (0x42415345) | 0xEDFAF516 | 0x00FBEF00 | 240
'CFF ' (0x43464620) | 0x696BDA8A | 0x0003F7BC | 16250689
'DSIG' (0x44534947) | 0x00000001 | 0x00FFECFC | 8
'GDEF' (0x47444546) | 0x020E0201 | 0x00FFED04 | 28
'GPOS' (0x47504F53) | 0x0EB8AF1A | 0x00FFED20 | 47386
'GSUB' (0x47535542) | 0xD0728B36 | 0x0100A63C | 177698
'OS/2' (0x4F532F32) | 0x92B910B0 | 0x00000180 | 96
'VORG' (0x564F5247) | 0xB042CD0A | 0x01035C60 | 876
'cmap' (0x636D6170) | 0x96E15049 | 0x00000B1C | 257151
'head' (0x68656164) | 0x1837A009 | 0x0000011C | 54
'hhea' (0x68686561) | 0x0C140872 | 0x00000154 | 36
'hmtx' (0x686D7478) | 0x1B0CBDAC | 0x01035FCC | 262132
'maxp' (0x6D617870) | 0xFFFF5000 | 0x00000178 | 6
'name' (0x6E616D65) | 0xCE24457C | 0x000001E0 | 2362
'post' (0x706F7374) | 0xFF860032 | 0x0003F79C | 32
'vhea' (0x76686561) | 0x0CA815AA | 0x01075FC0 | 36
'vmtx' (0x766D7478) | 0x98EC06F2 | 0x00FBEFF0 | 261386

version が 0x4F54544F で、'CFF ' テーブルがあるので、PostScript アウトラインです。
テーブルレコードは、タグの数値の昇順に並んでいます。
TTF ファイルの場合
==== offset table ====
version: 0x00010000 | numTables: 20
searchRange: 256 | entrySelector: 4 | rangeShift: 64

 tag                | checksum   | offset     | len
-----------------------------------------------------------
'BASE' (0x42415345) | 0x858F93E0 | 0x0000014C | 216
'GDEF' (0x47444546) | 0x00262FBF | 0x00000224 | 30
'GPOS' (0x47504F53) | 0x43C70945 | 0x00000244 | 4784
'GSUB' (0x47535542) | 0xAA360E49 | 0x000014F4 | 16590
'OS/2' (0x4F532F32) | 0x555687CD | 0x000055C4 | 96
'cmap' (0x636D6170) | 0x229F0A2A | 0x00005624 | 245775
'cvt ' (0x63767420) | 0x1E3D1ACC | 0x00041634 | 146
'fpgm' (0x6670676D) | 0xE27402A5 | 0x000416C8 | 116
'gasp' (0x67617370) | 0x00170009 | 0x0004173C | 16
'glyf' (0x676C7966) | 0x79D230F9 | 0x0004174C | 5593490
'head' (0x68656164) | 0x05F2BF62 | 0x005970E0 | 54
'hhea' (0x68686561) | 0x0CE4349E | 0x00597118 | 36
'hmtx' (0x686D7478) | 0x8F8CC666 | 0x0059713C | 48914
'loca' (0x6C6F6361) | 0x6B2586E6 | 0x005A3050 | 48960
'maxp' (0x6D617870) | 0x402D0343 | 0x005AEF90 | 32
'name' (0x6E616D65) | 0x2E48568C | 0x005AEFB0 | 2264
'post' (0x706F7374) | 0x0266A8C3 | 0x005AF888 | 113505
'prep' (0x70726570) | 0x3F711A3D | 0x005CB3EC | 10
'vhea' (0x76686561) | 0x0FEB07B2 | 0x005CB3F8 | 36
'vmtx' (0x766D7478) | 0xACAB56A6 | 0x005CB41C | 24480

version が 0x00010000 なので、TrueType アウトラインです。
TTC ファイルの場合
---- TTC header ----
tag:'ttcf' (0x74746366) | version: 1.0 | font nums: 2

==== offset table ====
version: 0x00010000 | numTables: 18
searchRange: 256 | entrySelector: 4 | rangeShift: 32

 tag                | checksum   | offset     | len
-----------------------------------------------------------
'GDEF' (0x47444546) | 0x002631BD | 0x0000026C | 30
'GSUB' (0x47535542) | 0x318E856A | 0x0000028C | 3518
'OS/2' (0x4F532F32) | 0x55B86FF6 | 0x0000104C | 96
'cmap' (0x636D6170) | 0x38F73E61 | 0x000010AC | 236166
'cvt ' (0x63767420) | 0x20CC21DC | 0x0003AB34 | 204
'fpgm' (0x6670676D) | 0x0F5DE35E | 0x0003AC00 | 113
'gasp' (0x67617370) | 0x00170009 | 0x0003AC74 | 16
'glyf' (0x676C7966) | 0xCBC0EEED | 0x0003AC84 | 7530768
'head' (0x68656164) | 0xF47D3A3D | 0x00769594 | 54
'hhea' (0x68686561) | 0x0BA737D7 | 0x007695CC | 36
'hmtx' (0x686D7478) | 0x3E38E58A | 0x007695F0 | 50600
'loca' (0x6C6F6361) | 0xD896AD5C | 0x00775B98 | 50916
'maxp' (0x6D617870) | 0x41E90549 | 0x0078227C | 32
'name' (0x6E616D65) | 0x89601DAF | 0x0078229C | 2438
'post' (0x706F7374) | 0xE54080A5 | 0x00782C24 | 120451
'prep' (0x70726570) | 0x3F71193D | 0x007A02A8 | 10
'vhea' (0x76686561) | 0x10083968 | 0x007A02B4 | 36
'vmtx' (0x766D7478) | 0xD3EFC50D | 0x007A02D8 | 50910

==== offset table ====
version: 0x00010000 | numTables: 18
searchRange: 256 | entrySelector: 4 | rangeShift: 32

 tag                | checksum   | offset     | len
-----------------------------------------------------------
'GDEF' (0x47444546) | 0x002631BD | 0x0000026C | 30
'GSUB' (0x47535542) | 0x9DCCFA49 | 0x007AC9B8 | 3546
'OS/2' (0x4F532F32) | 0x55706F79 | 0x007AD794 | 96
'cmap' (0x636D6170) | 0x817507EC | 0x007AD7F4 | 235446
'cvt ' (0x63767420) | 0x20CC21DC | 0x0003AB34 | 204
'fpgm' (0x6670676D) | 0x0F5DE35E | 0x0003AC00 | 113
'gasp' (0x67617370) | 0x00170009 | 0x0003AC74 | 16
'glyf' (0x676C7966) | 0xCBC0EEED | 0x0003AC84 | 7530768
'head' (0x68656164) | 0xF47D3775 | 0x007E6FAC | 54
'hhea' (0x68686561) | 0x0BA737D7 | 0x007695CC | 36
'hmtx' (0x686D7478) | 0x3E38E58A | 0x007695F0 | 50600
'loca' (0x6C6F6361) | 0xD896AD5C | 0x00775B98 | 50916
'maxp' (0x6D617870) | 0x41E90549 | 0x0078227C | 32
'name' (0x6E616D65) | 0x07271158 | 0x007E6FE4 | 2466
'post' (0x706F7374) | 0xE54080A5 | 0x00782C24 | 120451
'prep' (0x70726570) | 0x3F71193D | 0x007A02A8 | 10
'vhea' (0x76686561) | 0x10083968 | 0x007A02B4 | 36
'vmtx' (0x766D7478) | 0xD3EFC50D | 0x007A02D8 | 50910

各フォントごとに、オフセットテーブルがあります。

なお、1番目と2番目のフォントで、いくつかテーブルデータのオフセット位置が同じものがあります。
('GDEF' や 'cvt ' など)

複数のフォント格納時、完全に一致するテーブルデータがある場合は、複数のフォントで同じテーブルデータを使うことで、サイズを節約することができます。