TrueType Font File: C++98/STL parsing library

A TrueType font file contains data, in table format, that comprises an outline font.

File extension

ttf

KS implementation details

License: MIT

References

This page hosts a formal specification of TrueType Font File using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++98/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.ttf", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    ttf_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.offset_table() // => get offset table

C++98/STL source code to parse TrueType Font File

ttf.h

#ifndef TTF_H_
#define TTF_H_

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif

/**
 * A TrueType font file contains data, in table format, that comprises
 * an outline font.
 * \sa https://web.archive.org/web/20160410081432/https://www.microsoft.com/typography/tt/ttf_spec/ttch02.doc Source
 */

class ttf_t : public kaitai::kstruct {

public:
    class post_t;
    class name_t;
    class head_t;
    class prep_t;
    class hhea_t;
    class fpgm_t;
    class kern_t;
    class dir_table_entry_t;
    class os2_t;
    class fixed_t;
    class glyf_t;
    class cvt_t;
    class maxp_t;
    class maxp_version10_body_t;
    class offset_table_t;
    class cmap_t;

    ttf_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ttf_t* p__root = 0);

private:
    void _read();
    void _clean_up();

public:
    ~ttf_t();

    class post_t : public kaitai::kstruct {

    public:
        class format20_t;

        post_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~post_t();

        class format20_t : public kaitai::kstruct {

        public:
            class pascal_string_t;

            format20_t(kaitai::kstream* p__io, ttf_t::post_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~format20_t();

            class pascal_string_t : public kaitai::kstruct {

            public:

                pascal_string_t(kaitai::kstream* p__io, ttf_t::post_t::format20_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~pascal_string_t();

            private:
                uint8_t m_length;
                std::string m_value;
                bool n_value;

            public:
                bool _is_null_value() { value(); return n_value; };

            private:
                ttf_t* m__root;
                ttf_t::post_t::format20_t* m__parent;

            public:
                uint8_t length() const { return m_length; }
                std::string value() const { return m_value; }
                ttf_t* _root() const { return m__root; }
                ttf_t::post_t::format20_t* _parent() const { return m__parent; }
            };

        private:
            uint16_t m_number_of_glyphs;
            std::vector<uint16_t>* m_glyph_name_index;
            std::vector<pascal_string_t*>* m_glyph_names;
            ttf_t* m__root;
            ttf_t::post_t* m__parent;

        public:
            uint16_t number_of_glyphs() const { return m_number_of_glyphs; }
            std::vector<uint16_t>* glyph_name_index() const { return m_glyph_name_index; }
            std::vector<pascal_string_t*>* glyph_names() const { return m_glyph_names; }
            ttf_t* _root() const { return m__root; }
            ttf_t::post_t* _parent() const { return m__parent; }
        };

    private:
        fixed_t* m_format;
        fixed_t* m_italic_angle;
        int16_t m_underline_position;
        int16_t m_underline_thichness;
        uint32_t m_is_fixed_pitch;
        uint32_t m_min_mem_type42;
        uint32_t m_max_mem_type42;
        uint32_t m_min_mem_type1;
        uint32_t m_max_mem_type1;
        format20_t* m_format20;
        bool n_format20;

    public:
        bool _is_null_format20() { format20(); return n_format20; };

    private:
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        fixed_t* format() const { return m_format; }
        fixed_t* italic_angle() const { return m_italic_angle; }
        int16_t underline_position() const { return m_underline_position; }
        int16_t underline_thichness() const { return m_underline_thichness; }
        uint32_t is_fixed_pitch() const { return m_is_fixed_pitch; }
        uint32_t min_mem_type42() const { return m_min_mem_type42; }
        uint32_t max_mem_type42() const { return m_max_mem_type42; }
        uint32_t min_mem_type1() const { return m_min_mem_type1; }
        uint32_t max_mem_type1() const { return m_max_mem_type1; }
        format20_t* format20() const { return m_format20; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    /**
     * Name table is meant to include human-readable string metadata
     * that describes font: name of the font, its styles, copyright &
     * trademark notices, vendor and designer info, etc.
     * 
     * The table includes a list of "name records", each of which
     * corresponds to a single metadata entry.
     * \sa https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html Source
     */

    class name_t : public kaitai::kstruct {

    public:
        class name_record_t;

        enum platforms_t {
            PLATFORMS_UNICODE = 0,
            PLATFORMS_MACINTOSH = 1,
            PLATFORMS_RESERVED_2 = 2,
            PLATFORMS_MICROSOFT = 3
        };

        enum names_t {
            NAMES_COPYRIGHT = 0,
            NAMES_FONT_FAMILY = 1,
            NAMES_FONT_SUBFAMILY = 2,
            NAMES_UNIQUE_SUBFAMILY_ID = 3,
            NAMES_FULL_FONT_NAME = 4,
            NAMES_NAME_TABLE_VERSION = 5,
            NAMES_POSTSCRIPT_FONT_NAME = 6,
            NAMES_TRADEMARK = 7,
            NAMES_MANUFACTURER = 8,
            NAMES_DESIGNER = 9,
            NAMES_DESCRIPTION = 10,
            NAMES_URL_VENDOR = 11,
            NAMES_URL_DESIGNER = 12,
            NAMES_LICENSE = 13,
            NAMES_URL_LICENSE = 14,
            NAMES_RESERVED_15 = 15,
            NAMES_PREFERRED_FAMILY = 16,
            NAMES_PREFERRED_SUBFAMILY = 17,
            NAMES_COMPATIBLE_FULL_NAME = 18,
            NAMES_SAMPLE_TEXT = 19
        };

        name_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~name_t();

        class name_record_t : public kaitai::kstruct {

        public:

            name_record_t(kaitai::kstream* p__io, ttf_t::name_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~name_record_t();

        private:
            bool f_ascii_value;
            std::string m_ascii_value;

        public:
            std::string ascii_value();

        private:
            bool f_unicode_value;
            std::string m_unicode_value;

        public:
            std::string unicode_value();

        private:
            platforms_t m_platform_id;
            uint16_t m_encoding_id;
            uint16_t m_language_id;
            names_t m_name_id;
            uint16_t m_len_str;
            uint16_t m_ofs_str;
            ttf_t* m__root;
            ttf_t::name_t* m__parent;

        public:
            platforms_t platform_id() const { return m_platform_id; }
            uint16_t encoding_id() const { return m_encoding_id; }
            uint16_t language_id() const { return m_language_id; }
            names_t name_id() const { return m_name_id; }
            uint16_t len_str() const { return m_len_str; }
            uint16_t ofs_str() const { return m_ofs_str; }
            ttf_t* _root() const { return m__root; }
            ttf_t::name_t* _parent() const { return m__parent; }
        };

    private:
        uint16_t m_format_selector;
        uint16_t m_num_name_records;
        uint16_t m_ofs_strings;
        std::vector<name_record_t*>* m_name_records;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        uint16_t format_selector() const { return m_format_selector; }
        uint16_t num_name_records() const { return m_num_name_records; }
        uint16_t ofs_strings() const { return m_ofs_strings; }
        std::vector<name_record_t*>* name_records() const { return m_name_records; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class head_t : public kaitai::kstruct {

    public:

        enum flags_t {
            FLAGS_BASELINE_AT_Y0 = 1,
            FLAGS_LEFT_SIDEBEARING_AT_X0 = 2,
            FLAGS_FLAG_DEPEND_ON_POINT_SIZE = 4,
            FLAGS_FLAG_FORCE_PPEM = 8,
            FLAGS_FLAG_MAY_ADVANCE_WIDTH = 16
        };

        enum font_direction_hint_t {
            FONT_DIRECTION_HINT_FULLY_MIXED_DIRECTIONAL_GLYPHS = 0,
            FONT_DIRECTION_HINT_ONLY_STRONGLY_LEFT_TO_RIGHT = 1,
            FONT_DIRECTION_HINT_STRONGLY_LEFT_TO_RIGHT_AND_NEUTRALS = 2
        };

        head_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~head_t();

    private:
        fixed_t* m_version;
        fixed_t* m_font_revision;
        uint32_t m_checksum_adjustment;
        std::string m_magic_number;
        flags_t m_flags;
        uint16_t m_units_per_em;
        uint64_t m_created;
        uint64_t m_modified;
        int16_t m_x_min;
        int16_t m_y_min;
        int16_t m_x_max;
        int16_t m_y_max;
        uint16_t m_mac_style;
        uint16_t m_lowest_rec_ppem;
        font_direction_hint_t m_font_direction_hint;
        int16_t m_index_to_loc_format;
        int16_t m_glyph_data_format;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        fixed_t* version() const { return m_version; }
        fixed_t* font_revision() const { return m_font_revision; }
        uint32_t checksum_adjustment() const { return m_checksum_adjustment; }
        std::string magic_number() const { return m_magic_number; }
        flags_t flags() const { return m_flags; }
        uint16_t units_per_em() const { return m_units_per_em; }
        uint64_t created() const { return m_created; }
        uint64_t modified() const { return m_modified; }
        int16_t x_min() const { return m_x_min; }
        int16_t y_min() const { return m_y_min; }
        int16_t x_max() const { return m_x_max; }
        int16_t y_max() const { return m_y_max; }
        uint16_t mac_style() const { return m_mac_style; }
        uint16_t lowest_rec_ppem() const { return m_lowest_rec_ppem; }
        font_direction_hint_t font_direction_hint() const { return m_font_direction_hint; }
        int16_t index_to_loc_format() const { return m_index_to_loc_format; }
        int16_t glyph_data_format() const { return m_glyph_data_format; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class prep_t : public kaitai::kstruct {

    public:

        prep_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~prep_t();

    private:
        std::string m_instructions;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        std::string instructions() const { return m_instructions; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class hhea_t : public kaitai::kstruct {

    public:

        hhea_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~hhea_t();

    private:
        fixed_t* m_version;
        int16_t m_ascender;
        int16_t m_descender;
        int16_t m_line_gap;
        uint16_t m_advance_width_max;
        int16_t m_min_left_side_bearing;
        int16_t m_min_right_side_bearing;
        int16_t m_x_max_extend;
        int16_t m_caret_slope_rise;
        int16_t m_caret_slope_run;
        std::string m_reserved;
        int16_t m_metric_data_format;
        uint16_t m_number_of_hmetrics;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        fixed_t* version() const { return m_version; }

        /**
         * Typographic ascent
         */
        int16_t ascender() const { return m_ascender; }

        /**
         * Typographic descent
         */
        int16_t descender() const { return m_descender; }

        /**
         * Typographic line gap. Negative LineGap values are treated as zero in Windows 3.1, System 6, and System 7.
         */
        int16_t line_gap() const { return m_line_gap; }

        /**
         * Maximum advance width value in `hmtx` table.
         */
        uint16_t advance_width_max() const { return m_advance_width_max; }

        /**
         * Minimum left sidebearing value in `hmtx` table.
         */
        int16_t min_left_side_bearing() const { return m_min_left_side_bearing; }

        /**
         * Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)).
         */
        int16_t min_right_side_bearing() const { return m_min_right_side_bearing; }

        /**
         * Max(lsb + (xMax - xMin)).
         */
        int16_t x_max_extend() const { return m_x_max_extend; }
        int16_t caret_slope_rise() const { return m_caret_slope_rise; }
        int16_t caret_slope_run() const { return m_caret_slope_run; }
        std::string reserved() const { return m_reserved; }
        int16_t metric_data_format() const { return m_metric_data_format; }
        uint16_t number_of_hmetrics() const { return m_number_of_hmetrics; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class fpgm_t : public kaitai::kstruct {

    public:

        fpgm_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~fpgm_t();

    private:
        std::string m_instructions;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        std::string instructions() const { return m_instructions; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class kern_t : public kaitai::kstruct {

    public:
        class subtable_t;

        kern_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~kern_t();

        class subtable_t : public kaitai::kstruct {

        public:
            class format0_t;

            subtable_t(kaitai::kstream* p__io, ttf_t::kern_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~subtable_t();

            class format0_t : public kaitai::kstruct {

            public:
                class kerning_pair_t;

                format0_t(kaitai::kstream* p__io, ttf_t::kern_t::subtable_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~format0_t();

                class kerning_pair_t : public kaitai::kstruct {

                public:

                    kerning_pair_t(kaitai::kstream* p__io, ttf_t::kern_t::subtable_t::format0_t* p__parent = 0, ttf_t* p__root = 0);

                private:
                    void _read();
                    void _clean_up();

                public:
                    ~kerning_pair_t();

                private:
                    uint16_t m_left;
                    uint16_t m_right;
                    int16_t m_value;
                    ttf_t* m__root;
                    ttf_t::kern_t::subtable_t::format0_t* m__parent;

                public:
                    uint16_t left() const { return m_left; }
                    uint16_t right() const { return m_right; }
                    int16_t value() const { return m_value; }
                    ttf_t* _root() const { return m__root; }
                    ttf_t::kern_t::subtable_t::format0_t* _parent() const { return m__parent; }
                };

            private:
                uint16_t m_pair_count;
                uint16_t m_search_range;
                uint16_t m_entry_selector;
                uint16_t m_range_shift;
                std::vector<kerning_pair_t*>* m_kerning_pairs;
                ttf_t* m__root;
                ttf_t::kern_t::subtable_t* m__parent;

            public:
                uint16_t pair_count() const { return m_pair_count; }
                uint16_t search_range() const { return m_search_range; }
                uint16_t entry_selector() const { return m_entry_selector; }
                uint16_t range_shift() const { return m_range_shift; }
                std::vector<kerning_pair_t*>* kerning_pairs() const { return m_kerning_pairs; }
                ttf_t* _root() const { return m__root; }
                ttf_t::kern_t::subtable_t* _parent() const { return m__parent; }
            };

        private:
            uint16_t m_version;
            uint16_t m_length;
            uint8_t m_format;
            uint64_t m_reserved;
            bool m_is_override;
            bool m_is_cross_stream;
            bool m_is_minimum;
            bool m_is_horizontal;
            format0_t* m_format0;
            bool n_format0;

        public:
            bool _is_null_format0() { format0(); return n_format0; };

        private:
            ttf_t* m__root;
            ttf_t::kern_t* m__parent;

        public:
            uint16_t version() const { return m_version; }
            uint16_t length() const { return m_length; }
            uint8_t format() const { return m_format; }
            uint64_t reserved() const { return m_reserved; }
            bool is_override() const { return m_is_override; }
            bool is_cross_stream() const { return m_is_cross_stream; }
            bool is_minimum() const { return m_is_minimum; }
            bool is_horizontal() const { return m_is_horizontal; }
            format0_t* format0() const { return m_format0; }
            ttf_t* _root() const { return m__root; }
            ttf_t::kern_t* _parent() const { return m__parent; }
        };

    private:
        uint16_t m_version;
        uint16_t m_subtable_count;
        std::vector<subtable_t*>* m_subtables;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        uint16_t version() const { return m_version; }
        uint16_t subtable_count() const { return m_subtable_count; }
        std::vector<subtable_t*>* subtables() const { return m_subtables; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class dir_table_entry_t : public kaitai::kstruct {

    public:

        dir_table_entry_t(kaitai::kstream* p__io, ttf_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~dir_table_entry_t();

    private:
        bool f_value;
        kaitai::kstruct* m_value;
        bool n_value;

    public:
        bool _is_null_value() { value(); return n_value; };

    private:

    public:
        kaitai::kstruct* value();

    private:
        std::string m_tag;
        uint32_t m_checksum;
        uint32_t m_offset;
        uint32_t m_length;
        ttf_t* m__root;
        ttf_t* m__parent;
        std::string m__raw_value;
        kaitai::kstream* m__io__raw_value;

    public:
        std::string tag() const { return m_tag; }
        uint32_t checksum() const { return m_checksum; }
        uint32_t offset() const { return m_offset; }
        uint32_t length() const { return m_length; }
        ttf_t* _root() const { return m__root; }
        ttf_t* _parent() const { return m__parent; }
        std::string _raw_value() const { return m__raw_value; }
        kaitai::kstream* _io__raw_value() const { return m__io__raw_value; }
    };

    /**
     * The OS/2 table consists of a set of metrics that are required by Windows and OS/2.
     */

    class os2_t : public kaitai::kstruct {

    public:
        class panose_t;
        class unicode_range_t;
        class code_page_range_t;

        enum weight_class_t {
            WEIGHT_CLASS_THIN = 100,
            WEIGHT_CLASS_EXTRA_LIGHT = 200,
            WEIGHT_CLASS_LIGHT = 300,
            WEIGHT_CLASS_NORMAL = 400,
            WEIGHT_CLASS_MEDIUM = 500,
            WEIGHT_CLASS_SEMI_BOLD = 600,
            WEIGHT_CLASS_BOLD = 700,
            WEIGHT_CLASS_EXTRA_BOLD = 800,
            WEIGHT_CLASS_BLACK = 900
        };

        enum width_class_t {
            WIDTH_CLASS_ULTRA_CONDENSED = 1,
            WIDTH_CLASS_EXTRA_CONDENSED = 2,
            WIDTH_CLASS_CONDENSED = 3,
            WIDTH_CLASS_SEMI_CONDENSED = 4,
            WIDTH_CLASS_NORMAL = 5,
            WIDTH_CLASS_SEMI_EXPANDED = 6,
            WIDTH_CLASS_EXPANDED = 7,
            WIDTH_CLASS_EXTRA_EXPANDED = 8,
            WIDTH_CLASS_ULTRA_EXPANDED = 9
        };

        enum fs_type_t {
            FS_TYPE_RESTRICTED_LICENSE_EMBEDDING = 2,
            FS_TYPE_PREVIEW_AND_PRINT_EMBEDDING = 4,
            FS_TYPE_EDITABLE_EMBEDDING = 8
        };

        enum fs_selection_t {
            FS_SELECTION_ITALIC = 1,
            FS_SELECTION_UNDERSCORE = 2,
            FS_SELECTION_NEGATIVE = 4,
            FS_SELECTION_OUTLINED = 8,
            FS_SELECTION_STRIKEOUT = 16,
            FS_SELECTION_BOLD = 32,
            FS_SELECTION_REGULAR = 64
        };

        os2_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~os2_t();

        class panose_t : public kaitai::kstruct {

        public:

            enum weight_t {
                WEIGHT_ANY = 0,
                WEIGHT_NO_FIT = 1,
                WEIGHT_VERY_LIGHT = 2,
                WEIGHT_LIGHT = 3,
                WEIGHT_THIN = 4,
                WEIGHT_BOOK = 5,
                WEIGHT_MEDIUM = 6,
                WEIGHT_DEMI = 7,
                WEIGHT_BOLD = 8,
                WEIGHT_HEAVY = 9,
                WEIGHT_BLACK = 10,
                WEIGHT_NORD = 11
            };

            enum proportion_t {
                PROPORTION_ANY = 0,
                PROPORTION_NO_FIT = 1,
                PROPORTION_OLD_STYLE = 2,
                PROPORTION_MODERN = 3,
                PROPORTION_EVEN_WIDTH = 4,
                PROPORTION_EXPANDED = 5,
                PROPORTION_CONDENSED = 6,
                PROPORTION_VERY_EXPANDED = 7,
                PROPORTION_VERY_CONDENSED = 8,
                PROPORTION_MONOSPACED = 9
            };

            enum family_kind_t {
                FAMILY_KIND_ANY = 0,
                FAMILY_KIND_NO_FIT = 1,
                FAMILY_KIND_TEXT_AND_DISPLAY = 2,
                FAMILY_KIND_SCRIPT = 3,
                FAMILY_KIND_DECORATIVE = 4,
                FAMILY_KIND_PICTORIAL = 5
            };

            enum letter_form_t {
                LETTER_FORM_ANY = 0,
                LETTER_FORM_NO_FIT = 1,
                LETTER_FORM_NORMAL_CONTACT = 2,
                LETTER_FORM_NORMAL_WEIGHTED = 3,
                LETTER_FORM_NORMAL_BOXED = 4,
                LETTER_FORM_NORMAL_FLATTENED = 5,
                LETTER_FORM_NORMAL_ROUNDED = 6,
                LETTER_FORM_NORMAL_OFF_CENTER = 7,
                LETTER_FORM_NORMAL_SQUARE = 8,
                LETTER_FORM_OBLIQUE_CONTACT = 9,
                LETTER_FORM_OBLIQUE_WEIGHTED = 10,
                LETTER_FORM_OBLIQUE_BOXED = 11,
                LETTER_FORM_OBLIQUE_FLATTENED = 12,
                LETTER_FORM_OBLIQUE_ROUNDED = 13,
                LETTER_FORM_OBLIQUE_OFF_CENTER = 14,
                LETTER_FORM_OBLIQUE_SQUARE = 15
            };

            enum serif_style_t {
                SERIF_STYLE_ANY = 0,
                SERIF_STYLE_NO_FIT = 1,
                SERIF_STYLE_COVE = 2,
                SERIF_STYLE_OBTUSE_COVE = 3,
                SERIF_STYLE_SQUARE_COVE = 4,
                SERIF_STYLE_OBTUSE_SQUARE_COVE = 5,
                SERIF_STYLE_SQUARE = 6,
                SERIF_STYLE_THIN = 7,
                SERIF_STYLE_BONE = 8,
                SERIF_STYLE_EXAGGERATED = 9,
                SERIF_STYLE_TRIANGLE = 10,
                SERIF_STYLE_NORMAL_SANS = 11,
                SERIF_STYLE_OBTUSE_SANS = 12,
                SERIF_STYLE_PERP_SANS = 13,
                SERIF_STYLE_FLARED = 14,
                SERIF_STYLE_ROUNDED = 15
            };

            enum x_height_t {
                X_HEIGHT_ANY = 0,
                X_HEIGHT_NO_FIT = 1,
                X_HEIGHT_CONSTANT_SMALL = 2,
                X_HEIGHT_CONSTANT_STANDARD = 3,
                X_HEIGHT_CONSTANT_LARGE = 4,
                X_HEIGHT_DUCKING_SMALL = 5,
                X_HEIGHT_DUCKING_STANDARD = 6,
                X_HEIGHT_DUCKING_LARGE = 7
            };

            enum arm_style_t {
                ARM_STYLE_ANY = 0,
                ARM_STYLE_NO_FIT = 1,
                ARM_STYLE_STRAIGHT_ARMS_HORIZONTAL = 2,
                ARM_STYLE_STRAIGHT_ARMS_WEDGE = 3,
                ARM_STYLE_STRAIGHT_ARMS_VERTICAL = 4,
                ARM_STYLE_STRAIGHT_ARMS_SINGLE_SERIF = 5,
                ARM_STYLE_STRAIGHT_ARMS_DOUBLE_SERIF = 6,
                ARM_STYLE_NON_STRAIGHT_ARMS_HORIZONTAL = 7,
                ARM_STYLE_NON_STRAIGHT_ARMS_WEDGE = 8,
                ARM_STYLE_NON_STRAIGHT_ARMS_VERTICAL = 9,
                ARM_STYLE_NON_STRAIGHT_ARMS_SINGLE_SERIF = 10,
                ARM_STYLE_NON_STRAIGHT_ARMS_DOUBLE_SERIF = 11
            };

            enum stroke_variation_t {
                STROKE_VARIATION_ANY = 0,
                STROKE_VARIATION_NO_FIT = 1,
                STROKE_VARIATION_GRADUAL_DIAGONAL = 2,
                STROKE_VARIATION_GRADUAL_TRANSITIONAL = 3,
                STROKE_VARIATION_GRADUAL_VERTICAL = 4,
                STROKE_VARIATION_GRADUAL_HORIZONTAL = 5,
                STROKE_VARIATION_RAPID_VERTICAL = 6,
                STROKE_VARIATION_RAPID_HORIZONTAL = 7,
                STROKE_VARIATION_INSTANT_VERTICAL = 8
            };

            enum contrast_t {
                CONTRAST_ANY = 0,
                CONTRAST_NO_FIT = 1,
                CONTRAST_NONE = 2,
                CONTRAST_VERY_LOW = 3,
                CONTRAST_LOW = 4,
                CONTRAST_MEDIUM_LOW = 5,
                CONTRAST_MEDIUM = 6,
                CONTRAST_MEDIUM_HIGH = 7,
                CONTRAST_HIGH = 8,
                CONTRAST_VERY_HIGH = 9
            };

            enum midline_t {
                MIDLINE_ANY = 0,
                MIDLINE_NO_FIT = 1,
                MIDLINE_STANDARD_TRIMMED = 2,
                MIDLINE_STANDARD_POINTED = 3,
                MIDLINE_STANDARD_SERIFED = 4,
                MIDLINE_HIGH_TRIMMED = 5,
                MIDLINE_HIGH_POINTED = 6,
                MIDLINE_HIGH_SERIFED = 7,
                MIDLINE_CONSTANT_TRIMMED = 8,
                MIDLINE_CONSTANT_POINTED = 9,
                MIDLINE_CONSTANT_SERIFED = 10,
                MIDLINE_LOW_TRIMMED = 11,
                MIDLINE_LOW_POINTED = 12,
                MIDLINE_LOW_SERIFED = 13
            };

            panose_t(kaitai::kstream* p__io, ttf_t::os2_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~panose_t();

        private:
            family_kind_t m_family_type;
            serif_style_t m_serif_style;
            weight_t m_weight;
            proportion_t m_proportion;
            contrast_t m_contrast;
            stroke_variation_t m_stroke_variation;
            arm_style_t m_arm_style;
            letter_form_t m_letter_form;
            midline_t m_midline;
            x_height_t m_x_height;
            ttf_t* m__root;
            ttf_t::os2_t* m__parent;

        public:
            family_kind_t family_type() const { return m_family_type; }
            serif_style_t serif_style() const { return m_serif_style; }
            weight_t weight() const { return m_weight; }
            proportion_t proportion() const { return m_proportion; }
            contrast_t contrast() const { return m_contrast; }
            stroke_variation_t stroke_variation() const { return m_stroke_variation; }
            arm_style_t arm_style() const { return m_arm_style; }
            letter_form_t letter_form() const { return m_letter_form; }
            midline_t midline() const { return m_midline; }
            x_height_t x_height() const { return m_x_height; }
            ttf_t* _root() const { return m__root; }
            ttf_t::os2_t* _parent() const { return m__parent; }
        };

        class unicode_range_t : public kaitai::kstruct {

        public:

            unicode_range_t(kaitai::kstream* p__io, ttf_t::os2_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~unicode_range_t();

        private:
            bool m_basic_latin;
            bool m_latin_1_supplement;
            bool m_latin_extended_a;
            bool m_latin_extended_b;
            bool m_ipa_extensions;
            bool m_spacing_modifier_letters;
            bool m_combining_diacritical_marks;
            bool m_basic_greek;
            bool m_greek_symbols_and_coptic;
            bool m_cyrillic;
            bool m_armenian;
            bool m_basic_hebrew;
            bool m_hebrew_extended;
            bool m_basic_arabic;
            bool m_arabic_extended;
            bool m_devanagari;
            bool m_bengali;
            bool m_gurmukhi;
            bool m_gujarati;
            bool m_oriya;
            bool m_tamil;
            bool m_telugu;
            bool m_kannada;
            bool m_malayalam;
            bool m_thai;
            bool m_lao;
            bool m_basic_georgian;
            bool m_georgian_extended;
            bool m_hangul_jamo;
            bool m_latin_extended_additional;
            bool m_greek_extended;
            bool m_general_punctuation;
            bool m_superscripts_and_subscripts;
            bool m_currency_symbols;
            bool m_combining_diacritical_marks_for_symbols;
            bool m_letterlike_symbols;
            bool m_number_forms;
            bool m_arrows;
            bool m_mathematical_operators;
            bool m_miscellaneous_technical;
            bool m_control_pictures;
            bool m_optical_character_recognition;
            bool m_enclosed_alphanumerics;
            bool m_box_drawing;
            bool m_block_elements;
            bool m_geometric_shapes;
            bool m_miscellaneous_symbols;
            bool m_dingbats;
            bool m_cjk_symbols_and_punctuation;
            bool m_hiragana;
            bool m_katakana;
            bool m_bopomofo;
            bool m_hangul_compatibility_jamo;
            bool m_cjk_miscellaneous;
            bool m_enclosed_cjk_letters_and_months;
            bool m_cjk_compatibility;
            bool m_hangul;
            bool m_reserved_for_unicode_subranges1;
            bool m_reserved_for_unicode_subranges2;
            bool m_cjk_unified_ideographs;
            bool m_private_use_area;
            bool m_cjk_compatibility_ideographs;
            bool m_alphabetic_presentation_forms;
            bool m_arabic_presentation_forms_a;
            bool m_combining_half_marks;
            bool m_cjk_compatibility_forms;
            bool m_small_form_variants;
            bool m_arabic_presentation_forms_b;
            bool m_halfwidth_and_fullwidth_forms;
            bool m_specials;
            std::string m_reserved;
            ttf_t* m__root;
            ttf_t::os2_t* m__parent;

        public:
            bool basic_latin() const { return m_basic_latin; }
            bool latin_1_supplement() const { return m_latin_1_supplement; }
            bool latin_extended_a() const { return m_latin_extended_a; }
            bool latin_extended_b() const { return m_latin_extended_b; }
            bool ipa_extensions() const { return m_ipa_extensions; }
            bool spacing_modifier_letters() const { return m_spacing_modifier_letters; }
            bool combining_diacritical_marks() const { return m_combining_diacritical_marks; }
            bool basic_greek() const { return m_basic_greek; }
            bool greek_symbols_and_coptic() const { return m_greek_symbols_and_coptic; }
            bool cyrillic() const { return m_cyrillic; }
            bool armenian() const { return m_armenian; }
            bool basic_hebrew() const { return m_basic_hebrew; }
            bool hebrew_extended() const { return m_hebrew_extended; }
            bool basic_arabic() const { return m_basic_arabic; }
            bool arabic_extended() const { return m_arabic_extended; }
            bool devanagari() const { return m_devanagari; }
            bool bengali() const { return m_bengali; }
            bool gurmukhi() const { return m_gurmukhi; }
            bool gujarati() const { return m_gujarati; }
            bool oriya() const { return m_oriya; }
            bool tamil() const { return m_tamil; }
            bool telugu() const { return m_telugu; }
            bool kannada() const { return m_kannada; }
            bool malayalam() const { return m_malayalam; }
            bool thai() const { return m_thai; }
            bool lao() const { return m_lao; }
            bool basic_georgian() const { return m_basic_georgian; }
            bool georgian_extended() const { return m_georgian_extended; }
            bool hangul_jamo() const { return m_hangul_jamo; }
            bool latin_extended_additional() const { return m_latin_extended_additional; }
            bool greek_extended() const { return m_greek_extended; }
            bool general_punctuation() const { return m_general_punctuation; }
            bool superscripts_and_subscripts() const { return m_superscripts_and_subscripts; }
            bool currency_symbols() const { return m_currency_symbols; }
            bool combining_diacritical_marks_for_symbols() const { return m_combining_diacritical_marks_for_symbols; }
            bool letterlike_symbols() const { return m_letterlike_symbols; }
            bool number_forms() const { return m_number_forms; }
            bool arrows() const { return m_arrows; }
            bool mathematical_operators() const { return m_mathematical_operators; }
            bool miscellaneous_technical() const { return m_miscellaneous_technical; }
            bool control_pictures() const { return m_control_pictures; }
            bool optical_character_recognition() const { return m_optical_character_recognition; }
            bool enclosed_alphanumerics() const { return m_enclosed_alphanumerics; }
            bool box_drawing() const { return m_box_drawing; }
            bool block_elements() const { return m_block_elements; }
            bool geometric_shapes() const { return m_geometric_shapes; }
            bool miscellaneous_symbols() const { return m_miscellaneous_symbols; }
            bool dingbats() const { return m_dingbats; }
            bool cjk_symbols_and_punctuation() const { return m_cjk_symbols_and_punctuation; }
            bool hiragana() const { return m_hiragana; }
            bool katakana() const { return m_katakana; }
            bool bopomofo() const { return m_bopomofo; }
            bool hangul_compatibility_jamo() const { return m_hangul_compatibility_jamo; }
            bool cjk_miscellaneous() const { return m_cjk_miscellaneous; }
            bool enclosed_cjk_letters_and_months() const { return m_enclosed_cjk_letters_and_months; }
            bool cjk_compatibility() const { return m_cjk_compatibility; }
            bool hangul() const { return m_hangul; }
            bool reserved_for_unicode_subranges1() const { return m_reserved_for_unicode_subranges1; }
            bool reserved_for_unicode_subranges2() const { return m_reserved_for_unicode_subranges2; }
            bool cjk_unified_ideographs() const { return m_cjk_unified_ideographs; }
            bool private_use_area() const { return m_private_use_area; }
            bool cjk_compatibility_ideographs() const { return m_cjk_compatibility_ideographs; }
            bool alphabetic_presentation_forms() const { return m_alphabetic_presentation_forms; }
            bool arabic_presentation_forms_a() const { return m_arabic_presentation_forms_a; }
            bool combining_half_marks() const { return m_combining_half_marks; }
            bool cjk_compatibility_forms() const { return m_cjk_compatibility_forms; }
            bool small_form_variants() const { return m_small_form_variants; }
            bool arabic_presentation_forms_b() const { return m_arabic_presentation_forms_b; }
            bool halfwidth_and_fullwidth_forms() const { return m_halfwidth_and_fullwidth_forms; }
            bool specials() const { return m_specials; }
            std::string reserved() const { return m_reserved; }
            ttf_t* _root() const { return m__root; }
            ttf_t::os2_t* _parent() const { return m__parent; }
        };

        class code_page_range_t : public kaitai::kstruct {

        public:

            code_page_range_t(kaitai::kstream* p__io, ttf_t::os2_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~code_page_range_t();

        private:
            bool m_symbol_character_set;
            bool m_oem_character_set;
            bool m_macintosh_character_set;
            uint64_t m_reserved_for_alternate_ansi_oem;
            bool m_cp1361_korean_johab;
            bool m_cp950_chinese_traditional_chars_taiwan_and_hong_kong;
            bool m_cp949_korean_wansung;
            bool m_cp936_chinese_simplified_chars_prc_and_singapore;
            bool m_cp932_jis_japan;
            bool m_cp874_thai;
            uint64_t m_reserved_for_alternate_ansi;
            bool m_cp1257_windows_baltic;
            bool m_cp1256_arabic;
            bool m_cp1255_hebrew;
            bool m_cp1254_turkish;
            bool m_cp1253_greek;
            bool m_cp1251_cyrillic;
            bool m_cp1250_latin_2_eastern_europe;
            bool m_cp1252_latin_1;
            bool m_cp437_us;
            bool m_cp850_we_latin_1;
            bool m_cp708_arabic_asmo_708;
            bool m_cp737_greek_former_437_g;
            bool m_cp775_ms_dos_baltic;
            bool m_cp852_latin_2;
            bool m_cp855_ibm_cyrillic_primarily_russian;
            bool m_cp857_ibm_turkish;
            bool m_cp860_ms_dos_portuguese;
            bool m_cp861_ms_dos_icelandic;
            bool m_cp862_hebrew;
            bool m_cp863_ms_dos_canadian_french;
            bool m_cp864_arabic;
            bool m_cp865_ms_dos_nordic;
            bool m_cp866_ms_dos_russian;
            bool m_cp869_ibm_greek;
            uint64_t m_reserved_for_oem;
            ttf_t* m__root;
            ttf_t::os2_t* m__parent;

        public:
            bool symbol_character_set() const { return m_symbol_character_set; }
            bool oem_character_set() const { return m_oem_character_set; }
            bool macintosh_character_set() const { return m_macintosh_character_set; }
            uint64_t reserved_for_alternate_ansi_oem() const { return m_reserved_for_alternate_ansi_oem; }
            bool cp1361_korean_johab() const { return m_cp1361_korean_johab; }
            bool cp950_chinese_traditional_chars_taiwan_and_hong_kong() const { return m_cp950_chinese_traditional_chars_taiwan_and_hong_kong; }
            bool cp949_korean_wansung() const { return m_cp949_korean_wansung; }
            bool cp936_chinese_simplified_chars_prc_and_singapore() const { return m_cp936_chinese_simplified_chars_prc_and_singapore; }
            bool cp932_jis_japan() const { return m_cp932_jis_japan; }
            bool cp874_thai() const { return m_cp874_thai; }
            uint64_t reserved_for_alternate_ansi() const { return m_reserved_for_alternate_ansi; }
            bool cp1257_windows_baltic() const { return m_cp1257_windows_baltic; }
            bool cp1256_arabic() const { return m_cp1256_arabic; }
            bool cp1255_hebrew() const { return m_cp1255_hebrew; }
            bool cp1254_turkish() const { return m_cp1254_turkish; }
            bool cp1253_greek() const { return m_cp1253_greek; }
            bool cp1251_cyrillic() const { return m_cp1251_cyrillic; }
            bool cp1250_latin_2_eastern_europe() const { return m_cp1250_latin_2_eastern_europe; }
            bool cp1252_latin_1() const { return m_cp1252_latin_1; }
            bool cp437_us() const { return m_cp437_us; }
            bool cp850_we_latin_1() const { return m_cp850_we_latin_1; }
            bool cp708_arabic_asmo_708() const { return m_cp708_arabic_asmo_708; }
            bool cp737_greek_former_437_g() const { return m_cp737_greek_former_437_g; }
            bool cp775_ms_dos_baltic() const { return m_cp775_ms_dos_baltic; }
            bool cp852_latin_2() const { return m_cp852_latin_2; }
            bool cp855_ibm_cyrillic_primarily_russian() const { return m_cp855_ibm_cyrillic_primarily_russian; }
            bool cp857_ibm_turkish() const { return m_cp857_ibm_turkish; }
            bool cp860_ms_dos_portuguese() const { return m_cp860_ms_dos_portuguese; }
            bool cp861_ms_dos_icelandic() const { return m_cp861_ms_dos_icelandic; }
            bool cp862_hebrew() const { return m_cp862_hebrew; }
            bool cp863_ms_dos_canadian_french() const { return m_cp863_ms_dos_canadian_french; }
            bool cp864_arabic() const { return m_cp864_arabic; }
            bool cp865_ms_dos_nordic() const { return m_cp865_ms_dos_nordic; }
            bool cp866_ms_dos_russian() const { return m_cp866_ms_dos_russian; }
            bool cp869_ibm_greek() const { return m_cp869_ibm_greek; }
            uint64_t reserved_for_oem() const { return m_reserved_for_oem; }
            ttf_t* _root() const { return m__root; }
            ttf_t::os2_t* _parent() const { return m__parent; }
        };

    private:
        uint16_t m_version;
        int16_t m_x_avg_char_width;
        weight_class_t m_weight_class;
        width_class_t m_width_class;
        fs_type_t m_fs_type;
        int16_t m_y_subscript_x_size;
        int16_t m_y_subscript_y_size;
        int16_t m_y_subscript_x_offset;
        int16_t m_y_subscript_y_offset;
        int16_t m_y_superscript_x_size;
        int16_t m_y_superscript_y_size;
        int16_t m_y_superscript_x_offset;
        int16_t m_y_superscript_y_offset;
        int16_t m_y_strikeout_size;
        int16_t m_y_strikeout_position;
        int16_t m_s_family_class;
        panose_t* m_panose;
        unicode_range_t* m_unicode_range;
        std::string m_ach_vend_id;
        fs_selection_t m_selection;
        uint16_t m_first_char_index;
        uint16_t m_last_char_index;
        int16_t m_typo_ascender;
        int16_t m_typo_descender;
        int16_t m_typo_line_gap;
        uint16_t m_win_ascent;
        uint16_t m_win_descent;
        code_page_range_t* m_code_page_range;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:

        /**
         * The version number for this OS/2 table.
         */
        uint16_t version() const { return m_version; }

        /**
         * The Average Character Width parameter specifies the arithmetic average of the escapement (width) of all of the 26 lowercase letters a through z of the Latin alphabet and the space character. If any of the 26 lowercase letters are not present, this parameter should equal the weighted average of all glyphs in the font. For non-UGL (platform 3, encoding 0) fonts, use the unweighted average.
         */
        int16_t x_avg_char_width() const { return m_x_avg_char_width; }

        /**
         * Indicates the visual weight (degree of blackness or thickness of strokes) of the characters in the font.
         */
        weight_class_t weight_class() const { return m_weight_class; }

        /**
         * Indicates a relative change from the normal aspect ratio (width to height ratio) as specified by a font designer for the glyphs in a font.
         */
        width_class_t width_class() const { return m_width_class; }

        /**
         * Indicates font embedding licensing rights for the font. Embeddable fonts may be stored in a document. When a document with embedded fonts is opened on a system that does not have the font installed (the remote system), the embedded font may be loaded for temporary (and in some cases, permanent) use on that system by an embedding-aware application. Embedding licensing rights are granted by the vendor of the font.
         */
        fs_type_t fs_type() const { return m_fs_type; }

        /**
         * The recommended horizontal size in font design units for subscripts for this font.
         */
        int16_t y_subscript_x_size() const { return m_y_subscript_x_size; }

        /**
         * The recommended vertical size in font design units for subscripts for this font.
         */
        int16_t y_subscript_y_size() const { return m_y_subscript_y_size; }

        /**
         * The recommended horizontal offset in font design untis for subscripts for this font.
         */
        int16_t y_subscript_x_offset() const { return m_y_subscript_x_offset; }

        /**
         * The recommended vertical offset in font design units from the baseline for subscripts for this font.
         */
        int16_t y_subscript_y_offset() const { return m_y_subscript_y_offset; }

        /**
         * The recommended horizontal size in font design units for superscripts for this font.
         */
        int16_t y_superscript_x_size() const { return m_y_superscript_x_size; }

        /**
         * The recommended vertical size in font design units for superscripts for this font.
         */
        int16_t y_superscript_y_size() const { return m_y_superscript_y_size; }

        /**
         * The recommended horizontal offset in font design units for superscripts for this font.
         */
        int16_t y_superscript_x_offset() const { return m_y_superscript_x_offset; }

        /**
         * The recommended vertical offset in font design units from the baseline for superscripts for this font.
         */
        int16_t y_superscript_y_offset() const { return m_y_superscript_y_offset; }

        /**
         * Width of the strikeout stroke in font design units.
         */
        int16_t y_strikeout_size() const { return m_y_strikeout_size; }

        /**
         * The position of the strikeout stroke relative to the baseline in font design units.
         */
        int16_t y_strikeout_position() const { return m_y_strikeout_position; }

        /**
         * This parameter is a classification of font-family design.
         */
        int16_t s_family_class() const { return m_s_family_class; }
        panose_t* panose() const { return m_panose; }
        unicode_range_t* unicode_range() const { return m_unicode_range; }

        /**
         * The four character identifier for the vendor of the given type face.
         */
        std::string ach_vend_id() const { return m_ach_vend_id; }

        /**
         * Contains information concerning the nature of the font patterns
         */
        fs_selection_t selection() const { return m_selection; }

        /**
         * The minimum Unicode index (character code) in this font, according to the cmap subtable for platform ID 3 and encoding ID 0 or 1.
         */
        uint16_t first_char_index() const { return m_first_char_index; }

        /**
         * The maximum Unicode index (character code) in this font, according to the cmap subtable for platform ID 3 and encoding ID 0 or 1.
         */
        uint16_t last_char_index() const { return m_last_char_index; }

        /**
         * The typographic ascender for this font.
         */
        int16_t typo_ascender() const { return m_typo_ascender; }

        /**
         * The typographic descender for this font.
         */
        int16_t typo_descender() const { return m_typo_descender; }

        /**
         * The typographic line gap for this font.
         */
        int16_t typo_line_gap() const { return m_typo_line_gap; }

        /**
         * The ascender metric for Windows.
         */
        uint16_t win_ascent() const { return m_win_ascent; }

        /**
         * The descender metric for Windows.
         */
        uint16_t win_descent() const { return m_win_descent; }

        /**
         * This field is used to specify the code pages encompassed by the font file in the `cmap` subtable for platform 3, encoding ID 1 (Microsoft platform).
         */
        code_page_range_t* code_page_range() const { return m_code_page_range; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class fixed_t : public kaitai::kstruct {

    public:

        fixed_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~fixed_t();

    private:
        uint16_t m_major;
        uint16_t m_minor;
        ttf_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        uint16_t major() const { return m_major; }
        uint16_t minor() const { return m_minor; }
        ttf_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class glyf_t : public kaitai::kstruct {

    public:
        class simple_glyph_t;

        glyf_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~glyf_t();

        class simple_glyph_t : public kaitai::kstruct {

        public:
            class flag_t;

            simple_glyph_t(kaitai::kstream* p__io, ttf_t::glyf_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~simple_glyph_t();

            class flag_t : public kaitai::kstruct {

            public:

                flag_t(kaitai::kstream* p__io, ttf_t::glyf_t::simple_glyph_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~flag_t();

            private:
                uint64_t m_reserved;
                bool m_y_is_same;
                bool m_x_is_same;
                bool m_repeat;
                bool m_y_short_vector;
                bool m_x_short_vector;
                bool m_on_curve;
                uint8_t m_repeat_value;
                bool n_repeat_value;

            public:
                bool _is_null_repeat_value() { repeat_value(); return n_repeat_value; };

            private:
                ttf_t* m__root;
                ttf_t::glyf_t::simple_glyph_t* m__parent;

            public:
                uint64_t reserved() const { return m_reserved; }
                bool y_is_same() const { return m_y_is_same; }
                bool x_is_same() const { return m_x_is_same; }
                bool repeat() const { return m_repeat; }
                bool y_short_vector() const { return m_y_short_vector; }
                bool x_short_vector() const { return m_x_short_vector; }
                bool on_curve() const { return m_on_curve; }
                uint8_t repeat_value() const { return m_repeat_value; }
                ttf_t* _root() const { return m__root; }
                ttf_t::glyf_t::simple_glyph_t* _parent() const { return m__parent; }
            };

        private:
            bool f_point_count;
            int32_t m_point_count;

        public:
            int32_t point_count();

        private:
            std::vector<uint16_t>* m_end_pts_of_contours;
            uint16_t m_instruction_length;
            std::string m_instructions;
            std::vector<flag_t*>* m_flags;
            ttf_t* m__root;
            ttf_t::glyf_t* m__parent;

        public:
            std::vector<uint16_t>* end_pts_of_contours() const { return m_end_pts_of_contours; }
            uint16_t instruction_length() const { return m_instruction_length; }
            std::string instructions() const { return m_instructions; }
            std::vector<flag_t*>* flags() const { return m_flags; }
            ttf_t* _root() const { return m__root; }
            ttf_t::glyf_t* _parent() const { return m__parent; }
        };

    private:
        int16_t m_number_of_contours;
        int16_t m_x_min;
        int16_t m_y_min;
        int16_t m_x_max;
        int16_t m_y_max;
        simple_glyph_t* m_value;
        bool n_value;

    public:
        bool _is_null_value() { value(); return n_value; };

    private:
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        int16_t number_of_contours() const { return m_number_of_contours; }
        int16_t x_min() const { return m_x_min; }
        int16_t y_min() const { return m_y_min; }
        int16_t x_max() const { return m_x_max; }
        int16_t y_max() const { return m_y_max; }
        simple_glyph_t* value() const { return m_value; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    /**
     * cvt  - Control Value Table This table contains a list of values that can be referenced by instructions. They can be used, among other things, to control characteristics for different glyphs.
     */

    class cvt_t : public kaitai::kstruct {

    public:

        cvt_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~cvt_t();

    private:
        std::vector<int16_t>* m_fwords;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        std::vector<int16_t>* fwords() const { return m_fwords; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class maxp_t : public kaitai::kstruct {

    public:

        maxp_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~maxp_t();

    private:
        bool f_is_version10;
        bool m_is_version10;

    public:
        bool is_version10();

    private:
        fixed_t* m_table_version_number;
        uint16_t m_num_glyphs;
        maxp_version10_body_t* m_version10_body;
        bool n_version10_body;

    public:
        bool _is_null_version10_body() { version10_body(); return n_version10_body; };

    private:
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:

        /**
         * 0x00010000 for version 1.0.
         */
        fixed_t* table_version_number() const { return m_table_version_number; }

        /**
         * The number of glyphs in the font.
         */
        uint16_t num_glyphs() const { return m_num_glyphs; }
        maxp_version10_body_t* version10_body() const { return m_version10_body; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

    class maxp_version10_body_t : public kaitai::kstruct {

    public:

        maxp_version10_body_t(kaitai::kstream* p__io, ttf_t::maxp_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~maxp_version10_body_t();

    private:
        uint16_t m_max_points;
        uint16_t m_max_contours;
        uint16_t m_max_composite_points;
        uint16_t m_max_composite_contours;
        uint16_t m_max_zones;
        uint16_t m_max_twilight_points;
        uint16_t m_max_storage;
        uint16_t m_max_function_defs;
        uint16_t m_max_instruction_defs;
        uint16_t m_max_stack_elements;
        uint16_t m_max_size_of_instructions;
        uint16_t m_max_component_elements;
        uint16_t m_max_component_depth;
        ttf_t* m__root;
        ttf_t::maxp_t* m__parent;

    public:

        /**
         * Maximum points in a non-composite glyph.
         */
        uint16_t max_points() const { return m_max_points; }

        /**
         * Maximum contours in a non-composite glyph.
         */
        uint16_t max_contours() const { return m_max_contours; }

        /**
         * Maximum points in a composite glyph.
         */
        uint16_t max_composite_points() const { return m_max_composite_points; }

        /**
         * Maximum contours in a composite glyph.
         */
        uint16_t max_composite_contours() const { return m_max_composite_contours; }

        /**
         * 1 if instructions do not use the twilight zone (Z0), or 2 if instructions do use Z0; should be set to 2 in most cases.
         */
        uint16_t max_zones() const { return m_max_zones; }

        /**
         * Maximum points used in Z0.
         */
        uint16_t max_twilight_points() const { return m_max_twilight_points; }

        /**
         * Number of Storage Area locations.
         */
        uint16_t max_storage() const { return m_max_storage; }

        /**
         * Number of FDEFs.
         */
        uint16_t max_function_defs() const { return m_max_function_defs; }

        /**
         * Number of IDEFs.
         */
        uint16_t max_instruction_defs() const { return m_max_instruction_defs; }

        /**
         * Maximum stack depth.
         */
        uint16_t max_stack_elements() const { return m_max_stack_elements; }

        /**
         * Maximum byte count for glyph instructions.
         */
        uint16_t max_size_of_instructions() const { return m_max_size_of_instructions; }

        /**
         * Maximum number of components referenced at "top level" for any composite glyph.
         */
        uint16_t max_component_elements() const { return m_max_component_elements; }

        /**
         * Maximum levels of recursion; 1 for simple components.
         */
        uint16_t max_component_depth() const { return m_max_component_depth; }
        ttf_t* _root() const { return m__root; }
        ttf_t::maxp_t* _parent() const { return m__parent; }
    };

    class offset_table_t : public kaitai::kstruct {

    public:

        offset_table_t(kaitai::kstream* p__io, ttf_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~offset_table_t();

    private:
        fixed_t* m_sfnt_version;
        uint16_t m_num_tables;
        uint16_t m_search_range;
        uint16_t m_entry_selector;
        uint16_t m_range_shift;
        ttf_t* m__root;
        ttf_t* m__parent;

    public:
        fixed_t* sfnt_version() const { return m_sfnt_version; }
        uint16_t num_tables() const { return m_num_tables; }
        uint16_t search_range() const { return m_search_range; }
        uint16_t entry_selector() const { return m_entry_selector; }
        uint16_t range_shift() const { return m_range_shift; }
        ttf_t* _root() const { return m__root; }
        ttf_t* _parent() const { return m__parent; }
    };

    /**
     * cmap - Character To Glyph Index Mapping Table This table defines the mapping of character codes to the glyph index values used in the font.
     */

    class cmap_t : public kaitai::kstruct {

    public:
        class subtable_header_t;
        class subtable_t;

        cmap_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent = 0, ttf_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~cmap_t();

        class subtable_header_t : public kaitai::kstruct {

        public:

            subtable_header_t(kaitai::kstream* p__io, ttf_t::cmap_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~subtable_header_t();

        private:
            bool f_table;
            subtable_t* m_table;

        public:
            subtable_t* table();

        private:
            uint16_t m_platform_id;
            uint16_t m_encoding_id;
            uint32_t m_subtable_offset;
            ttf_t* m__root;
            ttf_t::cmap_t* m__parent;

        public:
            uint16_t platform_id() const { return m_platform_id; }
            uint16_t encoding_id() const { return m_encoding_id; }
            uint32_t subtable_offset() const { return m_subtable_offset; }
            ttf_t* _root() const { return m__root; }
            ttf_t::cmap_t* _parent() const { return m__parent; }
        };

        class subtable_t : public kaitai::kstruct {

        public:
            class byte_encoding_table_t;
            class high_byte_mapping_through_table_t;
            class segment_mapping_to_delta_values_t;
            class trimmed_table_mapping_t;

            enum subtable_format_t {
                SUBTABLE_FORMAT_BYTE_ENCODING_TABLE = 0,
                SUBTABLE_FORMAT_HIGH_BYTE_MAPPING_THROUGH_TABLE = 2,
                SUBTABLE_FORMAT_SEGMENT_MAPPING_TO_DELTA_VALUES = 4,
                SUBTABLE_FORMAT_TRIMMED_TABLE_MAPPING = 6
            };

            subtable_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_header_t* p__parent = 0, ttf_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~subtable_t();

            class byte_encoding_table_t : public kaitai::kstruct {

            public:

                byte_encoding_table_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~byte_encoding_table_t();

            private:
                std::string m_glyph_id_array;
                ttf_t* m__root;
                ttf_t::cmap_t::subtable_t* m__parent;

            public:
                std::string glyph_id_array() const { return m_glyph_id_array; }
                ttf_t* _root() const { return m__root; }
                ttf_t::cmap_t::subtable_t* _parent() const { return m__parent; }
            };

            class high_byte_mapping_through_table_t : public kaitai::kstruct {

            public:

                high_byte_mapping_through_table_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~high_byte_mapping_through_table_t();

            private:
                std::vector<uint16_t>* m_sub_header_keys;
                ttf_t* m__root;
                ttf_t::cmap_t::subtable_t* m__parent;

            public:
                std::vector<uint16_t>* sub_header_keys() const { return m_sub_header_keys; }
                ttf_t* _root() const { return m__root; }
                ttf_t::cmap_t::subtable_t* _parent() const { return m__parent; }
            };

            class segment_mapping_to_delta_values_t : public kaitai::kstruct {

            public:

                segment_mapping_to_delta_values_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~segment_mapping_to_delta_values_t();

            private:
                bool f_seg_count;
                int32_t m_seg_count;

            public:
                int32_t seg_count();

            private:
                uint16_t m_seg_count_x2;
                uint16_t m_search_range;
                uint16_t m_entry_selector;
                uint16_t m_range_shift;
                std::vector<uint16_t>* m_end_count;
                uint16_t m_reserved_pad;
                std::vector<uint16_t>* m_start_count;
                std::vector<uint16_t>* m_id_delta;
                std::vector<uint16_t>* m_id_range_offset;
                std::vector<uint16_t>* m_glyph_id_array;
                ttf_t* m__root;
                ttf_t::cmap_t::subtable_t* m__parent;

            public:
                uint16_t seg_count_x2() const { return m_seg_count_x2; }
                uint16_t search_range() const { return m_search_range; }
                uint16_t entry_selector() const { return m_entry_selector; }
                uint16_t range_shift() const { return m_range_shift; }
                std::vector<uint16_t>* end_count() const { return m_end_count; }
                uint16_t reserved_pad() const { return m_reserved_pad; }
                std::vector<uint16_t>* start_count() const { return m_start_count; }
                std::vector<uint16_t>* id_delta() const { return m_id_delta; }
                std::vector<uint16_t>* id_range_offset() const { return m_id_range_offset; }
                std::vector<uint16_t>* glyph_id_array() const { return m_glyph_id_array; }
                ttf_t* _root() const { return m__root; }
                ttf_t::cmap_t::subtable_t* _parent() const { return m__parent; }
            };

            class trimmed_table_mapping_t : public kaitai::kstruct {

            public:

                trimmed_table_mapping_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent = 0, ttf_t* p__root = 0);

            private:
                void _read();
                void _clean_up();

            public:
                ~trimmed_table_mapping_t();

            private:
                uint16_t m_first_code;
                uint16_t m_entry_count;
                std::vector<uint16_t>* m_glyph_id_array;
                ttf_t* m__root;
                ttf_t::cmap_t::subtable_t* m__parent;

            public:
                uint16_t first_code() const { return m_first_code; }
                uint16_t entry_count() const { return m_entry_count; }
                std::vector<uint16_t>* glyph_id_array() const { return m_glyph_id_array; }
                ttf_t* _root() const { return m__root; }
                ttf_t::cmap_t::subtable_t* _parent() const { return m__parent; }
            };

        private:
            subtable_format_t m_format;
            uint16_t m_length;
            uint16_t m_version;
            kaitai::kstruct* m_value;
            bool n_value;

        public:
            bool _is_null_value() { value(); return n_value; };

        private:
            ttf_t* m__root;
            ttf_t::cmap_t::subtable_header_t* m__parent;
            std::string m__raw_value;
            kaitai::kstream* m__io__raw_value;

        public:
            subtable_format_t format() const { return m_format; }
            uint16_t length() const { return m_length; }
            uint16_t version() const { return m_version; }
            kaitai::kstruct* value() const { return m_value; }
            ttf_t* _root() const { return m__root; }
            ttf_t::cmap_t::subtable_header_t* _parent() const { return m__parent; }
            std::string _raw_value() const { return m__raw_value; }
            kaitai::kstream* _io__raw_value() const { return m__io__raw_value; }
        };

    private:
        uint16_t m_version_number;
        uint16_t m_number_of_encoding_tables;
        std::vector<subtable_header_t*>* m_tables;
        ttf_t* m__root;
        ttf_t::dir_table_entry_t* m__parent;

    public:
        uint16_t version_number() const { return m_version_number; }
        uint16_t number_of_encoding_tables() const { return m_number_of_encoding_tables; }
        std::vector<subtable_header_t*>* tables() const { return m_tables; }
        ttf_t* _root() const { return m__root; }
        ttf_t::dir_table_entry_t* _parent() const { return m__parent; }
    };

private:
    offset_table_t* m_offset_table;
    std::vector<dir_table_entry_t*>* m_directory_table;
    ttf_t* m__root;
    kaitai::kstruct* m__parent;

public:
    offset_table_t* offset_table() const { return m_offset_table; }
    std::vector<dir_table_entry_t*>* directory_table() const { return m_directory_table; }
    ttf_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // TTF_H_

ttf.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "ttf.h"
#include "kaitai/exceptions.h"
#include <algorithm>

ttf_t::ttf_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_offset_table = 0;
    m_directory_table = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::_read() {
    m_offset_table = new offset_table_t(m__io, this, m__root);
    m_directory_table = new std::vector<dir_table_entry_t*>();
    const int l_directory_table = offset_table()->num_tables();
    for (int i = 0; i < l_directory_table; i++) {
        m_directory_table->push_back(new dir_table_entry_t(m__io, this, m__root));
    }
}

ttf_t::~ttf_t() {
    _clean_up();
}

void ttf_t::_clean_up() {
    if (m_offset_table) {
        delete m_offset_table; m_offset_table = 0;
    }
    if (m_directory_table) {
        for (std::vector<dir_table_entry_t*>::iterator it = m_directory_table->begin(); it != m_directory_table->end(); ++it) {
            delete *it;
        }
        delete m_directory_table; m_directory_table = 0;
    }
}

ttf_t::post_t::post_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m_italic_angle = 0;
    m_format20 = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::post_t::_read() {
    m_format = new fixed_t(m__io, this, m__root);
    m_italic_angle = new fixed_t(m__io, this, m__root);
    m_underline_position = m__io->read_s2be();
    m_underline_thichness = m__io->read_s2be();
    m_is_fixed_pitch = m__io->read_u4be();
    m_min_mem_type42 = m__io->read_u4be();
    m_max_mem_type42 = m__io->read_u4be();
    m_min_mem_type1 = m__io->read_u4be();
    m_max_mem_type1 = m__io->read_u4be();
    n_format20 = true;
    if ( ((format()->major() == 2) && (format()->minor() == 0)) ) {
        n_format20 = false;
        m_format20 = new format20_t(m__io, this, m__root);
    }
}

ttf_t::post_t::~post_t() {
    _clean_up();
}

void ttf_t::post_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (m_italic_angle) {
        delete m_italic_angle; m_italic_angle = 0;
    }
    if (!n_format20) {
        if (m_format20) {
            delete m_format20; m_format20 = 0;
        }
    }
}

ttf_t::post_t::format20_t::format20_t(kaitai::kstream* p__io, ttf_t::post_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_glyph_name_index = 0;
    m_glyph_names = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::post_t::format20_t::_read() {
    m_number_of_glyphs = m__io->read_u2be();
    m_glyph_name_index = new std::vector<uint16_t>();
    const int l_glyph_name_index = number_of_glyphs();
    for (int i = 0; i < l_glyph_name_index; i++) {
        m_glyph_name_index->push_back(m__io->read_u2be());
    }
    m_glyph_names = new std::vector<pascal_string_t*>();
    {
        int i = 0;
        pascal_string_t* _;
        do {
            _ = new pascal_string_t(m__io, this, m__root);
            m_glyph_names->push_back(_);
            i++;
        } while (!( ((_->length() == 0) || (_io()->is_eof())) ));
    }
}

ttf_t::post_t::format20_t::~format20_t() {
    _clean_up();
}

void ttf_t::post_t::format20_t::_clean_up() {
    if (m_glyph_name_index) {
        delete m_glyph_name_index; m_glyph_name_index = 0;
    }
    if (m_glyph_names) {
        for (std::vector<pascal_string_t*>::iterator it = m_glyph_names->begin(); it != m_glyph_names->end(); ++it) {
            delete *it;
        }
        delete m_glyph_names; m_glyph_names = 0;
    }
}

ttf_t::post_t::format20_t::pascal_string_t::pascal_string_t(kaitai::kstream* p__io, ttf_t::post_t::format20_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::post_t::format20_t::pascal_string_t::_read() {
    m_length = m__io->read_u1();
    n_value = true;
    if (length() != 0) {
        n_value = false;
        m_value = kaitai::kstream::bytes_to_str(m__io->read_bytes(length()), std::string("ascii"));
    }
}

ttf_t::post_t::format20_t::pascal_string_t::~pascal_string_t() {
    _clean_up();
}

void ttf_t::post_t::format20_t::pascal_string_t::_clean_up() {
    if (!n_value) {
    }
}

ttf_t::name_t::name_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_name_records = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::name_t::_read() {
    m_format_selector = m__io->read_u2be();
    m_num_name_records = m__io->read_u2be();
    m_ofs_strings = m__io->read_u2be();
    m_name_records = new std::vector<name_record_t*>();
    const int l_name_records = num_name_records();
    for (int i = 0; i < l_name_records; i++) {
        m_name_records->push_back(new name_record_t(m__io, this, m__root));
    }
}

ttf_t::name_t::~name_t() {
    _clean_up();
}

void ttf_t::name_t::_clean_up() {
    if (m_name_records) {
        for (std::vector<name_record_t*>::iterator it = m_name_records->begin(); it != m_name_records->end(); ++it) {
            delete *it;
        }
        delete m_name_records; m_name_records = 0;
    }
}

ttf_t::name_t::name_record_t::name_record_t(kaitai::kstream* p__io, ttf_t::name_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_ascii_value = false;
    f_unicode_value = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::name_t::name_record_t::_read() {
    m_platform_id = static_cast<ttf_t::name_t::platforms_t>(m__io->read_u2be());
    m_encoding_id = m__io->read_u2be();
    m_language_id = m__io->read_u2be();
    m_name_id = static_cast<ttf_t::name_t::names_t>(m__io->read_u2be());
    m_len_str = m__io->read_u2be();
    m_ofs_str = m__io->read_u2be();
}

ttf_t::name_t::name_record_t::~name_record_t() {
    _clean_up();
}

void ttf_t::name_t::name_record_t::_clean_up() {
    if (f_ascii_value) {
    }
    if (f_unicode_value) {
    }
}

std::string ttf_t::name_t::name_record_t::ascii_value() {
    if (f_ascii_value)
        return m_ascii_value;
    kaitai::kstream *io = _parent()->_io();
    std::streampos _pos = io->pos();
    io->seek((_parent()->ofs_strings() + ofs_str()));
    m_ascii_value = kaitai::kstream::bytes_to_str(io->read_bytes(len_str()), std::string("ascii"));
    io->seek(_pos);
    f_ascii_value = true;
    return m_ascii_value;
}

std::string ttf_t::name_t::name_record_t::unicode_value() {
    if (f_unicode_value)
        return m_unicode_value;
    kaitai::kstream *io = _parent()->_io();
    std::streampos _pos = io->pos();
    io->seek((_parent()->ofs_strings() + ofs_str()));
    m_unicode_value = kaitai::kstream::bytes_to_str(io->read_bytes(len_str()), std::string("utf-16be"));
    io->seek(_pos);
    f_unicode_value = true;
    return m_unicode_value;
}

ttf_t::head_t::head_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_version = 0;
    m_font_revision = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::head_t::_read() {
    m_version = new fixed_t(m__io, this, m__root);
    m_font_revision = new fixed_t(m__io, this, m__root);
    m_checksum_adjustment = m__io->read_u4be();
    m_magic_number = m__io->read_bytes(4);
    if (!(magic_number() == std::string("\x5F\x0F\x3C\xF5", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x5F\x0F\x3C\xF5", 4), magic_number(), _io(), std::string("/types/head/seq/3"));
    }
    m_flags = static_cast<ttf_t::head_t::flags_t>(m__io->read_u2be());
    m_units_per_em = m__io->read_u2be();
    m_created = m__io->read_u8be();
    m_modified = m__io->read_u8be();
    m_x_min = m__io->read_s2be();
    m_y_min = m__io->read_s2be();
    m_x_max = m__io->read_s2be();
    m_y_max = m__io->read_s2be();
    m_mac_style = m__io->read_u2be();
    m_lowest_rec_ppem = m__io->read_u2be();
    m_font_direction_hint = static_cast<ttf_t::head_t::font_direction_hint_t>(m__io->read_s2be());
    m_index_to_loc_format = m__io->read_s2be();
    m_glyph_data_format = m__io->read_s2be();
}

ttf_t::head_t::~head_t() {
    _clean_up();
}

void ttf_t::head_t::_clean_up() {
    if (m_version) {
        delete m_version; m_version = 0;
    }
    if (m_font_revision) {
        delete m_font_revision; m_font_revision = 0;
    }
}

ttf_t::prep_t::prep_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::prep_t::_read() {
    m_instructions = m__io->read_bytes_full();
}

ttf_t::prep_t::~prep_t() {
    _clean_up();
}

void ttf_t::prep_t::_clean_up() {
}

ttf_t::hhea_t::hhea_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_version = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::hhea_t::_read() {
    m_version = new fixed_t(m__io, this, m__root);
    m_ascender = m__io->read_s2be();
    m_descender = m__io->read_s2be();
    m_line_gap = m__io->read_s2be();
    m_advance_width_max = m__io->read_u2be();
    m_min_left_side_bearing = m__io->read_s2be();
    m_min_right_side_bearing = m__io->read_s2be();
    m_x_max_extend = m__io->read_s2be();
    m_caret_slope_rise = m__io->read_s2be();
    m_caret_slope_run = m__io->read_s2be();
    m_reserved = m__io->read_bytes(10);
    if (!(reserved() == std::string("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10), reserved(), _io(), std::string("/types/hhea/seq/10"));
    }
    m_metric_data_format = m__io->read_s2be();
    m_number_of_hmetrics = m__io->read_u2be();
}

ttf_t::hhea_t::~hhea_t() {
    _clean_up();
}

void ttf_t::hhea_t::_clean_up() {
    if (m_version) {
        delete m_version; m_version = 0;
    }
}

ttf_t::fpgm_t::fpgm_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::fpgm_t::_read() {
    m_instructions = m__io->read_bytes_full();
}

ttf_t::fpgm_t::~fpgm_t() {
    _clean_up();
}

void ttf_t::fpgm_t::_clean_up() {
}

ttf_t::kern_t::kern_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_subtables = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::kern_t::_read() {
    m_version = m__io->read_u2be();
    m_subtable_count = m__io->read_u2be();
    m_subtables = new std::vector<subtable_t*>();
    const int l_subtables = subtable_count();
    for (int i = 0; i < l_subtables; i++) {
        m_subtables->push_back(new subtable_t(m__io, this, m__root));
    }
}

ttf_t::kern_t::~kern_t() {
    _clean_up();
}

void ttf_t::kern_t::_clean_up() {
    if (m_subtables) {
        for (std::vector<subtable_t*>::iterator it = m_subtables->begin(); it != m_subtables->end(); ++it) {
            delete *it;
        }
        delete m_subtables; m_subtables = 0;
    }
}

ttf_t::kern_t::subtable_t::subtable_t(kaitai::kstream* p__io, ttf_t::kern_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format0 = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::kern_t::subtable_t::_read() {
    m_version = m__io->read_u2be();
    m_length = m__io->read_u2be();
    m_format = m__io->read_u1();
    m_reserved = m__io->read_bits_int_be(4);
    m_is_override = m__io->read_bits_int_be(1);
    m_is_cross_stream = m__io->read_bits_int_be(1);
    m_is_minimum = m__io->read_bits_int_be(1);
    m_is_horizontal = m__io->read_bits_int_be(1);
    m__io->align_to_byte();
    n_format0 = true;
    if (format() == 0) {
        n_format0 = false;
        m_format0 = new format0_t(m__io, this, m__root);
    }
}

ttf_t::kern_t::subtable_t::~subtable_t() {
    _clean_up();
}

void ttf_t::kern_t::subtable_t::_clean_up() {
    if (!n_format0) {
        if (m_format0) {
            delete m_format0; m_format0 = 0;
        }
    }
}

ttf_t::kern_t::subtable_t::format0_t::format0_t(kaitai::kstream* p__io, ttf_t::kern_t::subtable_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_kerning_pairs = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::kern_t::subtable_t::format0_t::_read() {
    m_pair_count = m__io->read_u2be();
    m_search_range = m__io->read_u2be();
    m_entry_selector = m__io->read_u2be();
    m_range_shift = m__io->read_u2be();
    m_kerning_pairs = new std::vector<kerning_pair_t*>();
    const int l_kerning_pairs = pair_count();
    for (int i = 0; i < l_kerning_pairs; i++) {
        m_kerning_pairs->push_back(new kerning_pair_t(m__io, this, m__root));
    }
}

ttf_t::kern_t::subtable_t::format0_t::~format0_t() {
    _clean_up();
}

void ttf_t::kern_t::subtable_t::format0_t::_clean_up() {
    if (m_kerning_pairs) {
        for (std::vector<kerning_pair_t*>::iterator it = m_kerning_pairs->begin(); it != m_kerning_pairs->end(); ++it) {
            delete *it;
        }
        delete m_kerning_pairs; m_kerning_pairs = 0;
    }
}

ttf_t::kern_t::subtable_t::format0_t::kerning_pair_t::kerning_pair_t(kaitai::kstream* p__io, ttf_t::kern_t::subtable_t::format0_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::kern_t::subtable_t::format0_t::kerning_pair_t::_read() {
    m_left = m__io->read_u2be();
    m_right = m__io->read_u2be();
    m_value = m__io->read_s2be();
}

ttf_t::kern_t::subtable_t::format0_t::kerning_pair_t::~kerning_pair_t() {
    _clean_up();
}

void ttf_t::kern_t::subtable_t::format0_t::kerning_pair_t::_clean_up() {
}

ttf_t::dir_table_entry_t::dir_table_entry_t(kaitai::kstream* p__io, ttf_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_value = 0;
    f_value = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::dir_table_entry_t::_read() {
    m_tag = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), std::string("ascii"));
    m_checksum = m__io->read_u4be();
    m_offset = m__io->read_u4be();
    m_length = m__io->read_u4be();
}

ttf_t::dir_table_entry_t::~dir_table_entry_t() {
    _clean_up();
}

void ttf_t::dir_table_entry_t::_clean_up() {
    if (f_value && !n_value) {
        if (m__io__raw_value) {
            delete m__io__raw_value; m__io__raw_value = 0;
        }
        if (m_value) {
            delete m_value; m_value = 0;
        }
    }
}

kaitai::kstruct* ttf_t::dir_table_entry_t::value() {
    if (f_value)
        return m_value;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(offset());
    n_value = true;
    {
        std::string on = tag();
        if (on == std::string("head")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new head_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("cvt ")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new cvt_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("prep")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new prep_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("kern")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new kern_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("hhea")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new hhea_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("post")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new post_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("OS/2")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new os2_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("name")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new name_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("maxp")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new maxp_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("glyf")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new glyf_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("fpgm")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new fpgm_t(m__io__raw_value, this, m__root);
        }
        else if (on == std::string("cmap")) {
            n_value = false;
            m__raw_value = io->read_bytes(length());
            m__io__raw_value = new kaitai::kstream(m__raw_value);
            m_value = new cmap_t(m__io__raw_value, this, m__root);
        }
        else {
            m__raw_value = io->read_bytes(length());
        }
    }
    io->seek(_pos);
    f_value = true;
    return m_value;
}

ttf_t::os2_t::os2_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_panose = 0;
    m_unicode_range = 0;
    m_code_page_range = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::os2_t::_read() {
    m_version = m__io->read_u2be();
    m_x_avg_char_width = m__io->read_s2be();
    m_weight_class = static_cast<ttf_t::os2_t::weight_class_t>(m__io->read_u2be());
    m_width_class = static_cast<ttf_t::os2_t::width_class_t>(m__io->read_u2be());
    m_fs_type = static_cast<ttf_t::os2_t::fs_type_t>(m__io->read_s2be());
    m_y_subscript_x_size = m__io->read_s2be();
    m_y_subscript_y_size = m__io->read_s2be();
    m_y_subscript_x_offset = m__io->read_s2be();
    m_y_subscript_y_offset = m__io->read_s2be();
    m_y_superscript_x_size = m__io->read_s2be();
    m_y_superscript_y_size = m__io->read_s2be();
    m_y_superscript_x_offset = m__io->read_s2be();
    m_y_superscript_y_offset = m__io->read_s2be();
    m_y_strikeout_size = m__io->read_s2be();
    m_y_strikeout_position = m__io->read_s2be();
    m_s_family_class = m__io->read_s2be();
    m_panose = new panose_t(m__io, this, m__root);
    m_unicode_range = new unicode_range_t(m__io, this, m__root);
    m_ach_vend_id = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), std::string("ascii"));
    m_selection = static_cast<ttf_t::os2_t::fs_selection_t>(m__io->read_u2be());
    m_first_char_index = m__io->read_u2be();
    m_last_char_index = m__io->read_u2be();
    m_typo_ascender = m__io->read_s2be();
    m_typo_descender = m__io->read_s2be();
    m_typo_line_gap = m__io->read_s2be();
    m_win_ascent = m__io->read_u2be();
    m_win_descent = m__io->read_u2be();
    m_code_page_range = new code_page_range_t(m__io, this, m__root);
}

ttf_t::os2_t::~os2_t() {
    _clean_up();
}

void ttf_t::os2_t::_clean_up() {
    if (m_panose) {
        delete m_panose; m_panose = 0;
    }
    if (m_unicode_range) {
        delete m_unicode_range; m_unicode_range = 0;
    }
    if (m_code_page_range) {
        delete m_code_page_range; m_code_page_range = 0;
    }
}

ttf_t::os2_t::panose_t::panose_t(kaitai::kstream* p__io, ttf_t::os2_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::os2_t::panose_t::_read() {
    m_family_type = static_cast<ttf_t::os2_t::panose_t::family_kind_t>(m__io->read_u1());
    m_serif_style = static_cast<ttf_t::os2_t::panose_t::serif_style_t>(m__io->read_u1());
    m_weight = static_cast<ttf_t::os2_t::panose_t::weight_t>(m__io->read_u1());
    m_proportion = static_cast<ttf_t::os2_t::panose_t::proportion_t>(m__io->read_u1());
    m_contrast = static_cast<ttf_t::os2_t::panose_t::contrast_t>(m__io->read_u1());
    m_stroke_variation = static_cast<ttf_t::os2_t::panose_t::stroke_variation_t>(m__io->read_u1());
    m_arm_style = static_cast<ttf_t::os2_t::panose_t::arm_style_t>(m__io->read_u1());
    m_letter_form = static_cast<ttf_t::os2_t::panose_t::letter_form_t>(m__io->read_u1());
    m_midline = static_cast<ttf_t::os2_t::panose_t::midline_t>(m__io->read_u1());
    m_x_height = static_cast<ttf_t::os2_t::panose_t::x_height_t>(m__io->read_u1());
}

ttf_t::os2_t::panose_t::~panose_t() {
    _clean_up();
}

void ttf_t::os2_t::panose_t::_clean_up() {
}

ttf_t::os2_t::unicode_range_t::unicode_range_t(kaitai::kstream* p__io, ttf_t::os2_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::os2_t::unicode_range_t::_read() {
    m_basic_latin = m__io->read_bits_int_be(1);
    m_latin_1_supplement = m__io->read_bits_int_be(1);
    m_latin_extended_a = m__io->read_bits_int_be(1);
    m_latin_extended_b = m__io->read_bits_int_be(1);
    m_ipa_extensions = m__io->read_bits_int_be(1);
    m_spacing_modifier_letters = m__io->read_bits_int_be(1);
    m_combining_diacritical_marks = m__io->read_bits_int_be(1);
    m_basic_greek = m__io->read_bits_int_be(1);
    m_greek_symbols_and_coptic = m__io->read_bits_int_be(1);
    m_cyrillic = m__io->read_bits_int_be(1);
    m_armenian = m__io->read_bits_int_be(1);
    m_basic_hebrew = m__io->read_bits_int_be(1);
    m_hebrew_extended = m__io->read_bits_int_be(1);
    m_basic_arabic = m__io->read_bits_int_be(1);
    m_arabic_extended = m__io->read_bits_int_be(1);
    m_devanagari = m__io->read_bits_int_be(1);
    m_bengali = m__io->read_bits_int_be(1);
    m_gurmukhi = m__io->read_bits_int_be(1);
    m_gujarati = m__io->read_bits_int_be(1);
    m_oriya = m__io->read_bits_int_be(1);
    m_tamil = m__io->read_bits_int_be(1);
    m_telugu = m__io->read_bits_int_be(1);
    m_kannada = m__io->read_bits_int_be(1);
    m_malayalam = m__io->read_bits_int_be(1);
    m_thai = m__io->read_bits_int_be(1);
    m_lao = m__io->read_bits_int_be(1);
    m_basic_georgian = m__io->read_bits_int_be(1);
    m_georgian_extended = m__io->read_bits_int_be(1);
    m_hangul_jamo = m__io->read_bits_int_be(1);
    m_latin_extended_additional = m__io->read_bits_int_be(1);
    m_greek_extended = m__io->read_bits_int_be(1);
    m_general_punctuation = m__io->read_bits_int_be(1);
    m_superscripts_and_subscripts = m__io->read_bits_int_be(1);
    m_currency_symbols = m__io->read_bits_int_be(1);
    m_combining_diacritical_marks_for_symbols = m__io->read_bits_int_be(1);
    m_letterlike_symbols = m__io->read_bits_int_be(1);
    m_number_forms = m__io->read_bits_int_be(1);
    m_arrows = m__io->read_bits_int_be(1);
    m_mathematical_operators = m__io->read_bits_int_be(1);
    m_miscellaneous_technical = m__io->read_bits_int_be(1);
    m_control_pictures = m__io->read_bits_int_be(1);
    m_optical_character_recognition = m__io->read_bits_int_be(1);
    m_enclosed_alphanumerics = m__io->read_bits_int_be(1);
    m_box_drawing = m__io->read_bits_int_be(1);
    m_block_elements = m__io->read_bits_int_be(1);
    m_geometric_shapes = m__io->read_bits_int_be(1);
    m_miscellaneous_symbols = m__io->read_bits_int_be(1);
    m_dingbats = m__io->read_bits_int_be(1);
    m_cjk_symbols_and_punctuation = m__io->read_bits_int_be(1);
    m_hiragana = m__io->read_bits_int_be(1);
    m_katakana = m__io->read_bits_int_be(1);
    m_bopomofo = m__io->read_bits_int_be(1);
    m_hangul_compatibility_jamo = m__io->read_bits_int_be(1);
    m_cjk_miscellaneous = m__io->read_bits_int_be(1);
    m_enclosed_cjk_letters_and_months = m__io->read_bits_int_be(1);
    m_cjk_compatibility = m__io->read_bits_int_be(1);
    m_hangul = m__io->read_bits_int_be(1);
    m_reserved_for_unicode_subranges1 = m__io->read_bits_int_be(1);
    m_reserved_for_unicode_subranges2 = m__io->read_bits_int_be(1);
    m_cjk_unified_ideographs = m__io->read_bits_int_be(1);
    m_private_use_area = m__io->read_bits_int_be(1);
    m_cjk_compatibility_ideographs = m__io->read_bits_int_be(1);
    m_alphabetic_presentation_forms = m__io->read_bits_int_be(1);
    m_arabic_presentation_forms_a = m__io->read_bits_int_be(1);
    m_combining_half_marks = m__io->read_bits_int_be(1);
    m_cjk_compatibility_forms = m__io->read_bits_int_be(1);
    m_small_form_variants = m__io->read_bits_int_be(1);
    m_arabic_presentation_forms_b = m__io->read_bits_int_be(1);
    m_halfwidth_and_fullwidth_forms = m__io->read_bits_int_be(1);
    m_specials = m__io->read_bits_int_be(1);
    m__io->align_to_byte();
    m_reserved = m__io->read_bytes(7);
}

ttf_t::os2_t::unicode_range_t::~unicode_range_t() {
    _clean_up();
}

void ttf_t::os2_t::unicode_range_t::_clean_up() {
}

ttf_t::os2_t::code_page_range_t::code_page_range_t(kaitai::kstream* p__io, ttf_t::os2_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::os2_t::code_page_range_t::_read() {
    m_symbol_character_set = m__io->read_bits_int_be(1);
    m_oem_character_set = m__io->read_bits_int_be(1);
    m_macintosh_character_set = m__io->read_bits_int_be(1);
    m_reserved_for_alternate_ansi_oem = m__io->read_bits_int_be(7);
    m_cp1361_korean_johab = m__io->read_bits_int_be(1);
    m_cp950_chinese_traditional_chars_taiwan_and_hong_kong = m__io->read_bits_int_be(1);
    m_cp949_korean_wansung = m__io->read_bits_int_be(1);
    m_cp936_chinese_simplified_chars_prc_and_singapore = m__io->read_bits_int_be(1);
    m_cp932_jis_japan = m__io->read_bits_int_be(1);
    m_cp874_thai = m__io->read_bits_int_be(1);
    m_reserved_for_alternate_ansi = m__io->read_bits_int_be(8);
    m_cp1257_windows_baltic = m__io->read_bits_int_be(1);
    m_cp1256_arabic = m__io->read_bits_int_be(1);
    m_cp1255_hebrew = m__io->read_bits_int_be(1);
    m_cp1254_turkish = m__io->read_bits_int_be(1);
    m_cp1253_greek = m__io->read_bits_int_be(1);
    m_cp1251_cyrillic = m__io->read_bits_int_be(1);
    m_cp1250_latin_2_eastern_europe = m__io->read_bits_int_be(1);
    m_cp1252_latin_1 = m__io->read_bits_int_be(1);
    m_cp437_us = m__io->read_bits_int_be(1);
    m_cp850_we_latin_1 = m__io->read_bits_int_be(1);
    m_cp708_arabic_asmo_708 = m__io->read_bits_int_be(1);
    m_cp737_greek_former_437_g = m__io->read_bits_int_be(1);
    m_cp775_ms_dos_baltic = m__io->read_bits_int_be(1);
    m_cp852_latin_2 = m__io->read_bits_int_be(1);
    m_cp855_ibm_cyrillic_primarily_russian = m__io->read_bits_int_be(1);
    m_cp857_ibm_turkish = m__io->read_bits_int_be(1);
    m_cp860_ms_dos_portuguese = m__io->read_bits_int_be(1);
    m_cp861_ms_dos_icelandic = m__io->read_bits_int_be(1);
    m_cp862_hebrew = m__io->read_bits_int_be(1);
    m_cp863_ms_dos_canadian_french = m__io->read_bits_int_be(1);
    m_cp864_arabic = m__io->read_bits_int_be(1);
    m_cp865_ms_dos_nordic = m__io->read_bits_int_be(1);
    m_cp866_ms_dos_russian = m__io->read_bits_int_be(1);
    m_cp869_ibm_greek = m__io->read_bits_int_be(1);
    m_reserved_for_oem = m__io->read_bits_int_be(16);
}

ttf_t::os2_t::code_page_range_t::~code_page_range_t() {
    _clean_up();
}

void ttf_t::os2_t::code_page_range_t::_clean_up() {
}

ttf_t::fixed_t::fixed_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::fixed_t::_read() {
    m_major = m__io->read_u2be();
    m_minor = m__io->read_u2be();
}

ttf_t::fixed_t::~fixed_t() {
    _clean_up();
}

void ttf_t::fixed_t::_clean_up() {
}

ttf_t::glyf_t::glyf_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_value = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::glyf_t::_read() {
    m_number_of_contours = m__io->read_s2be();
    m_x_min = m__io->read_s2be();
    m_y_min = m__io->read_s2be();
    m_x_max = m__io->read_s2be();
    m_y_max = m__io->read_s2be();
    n_value = true;
    if (number_of_contours() > 0) {
        n_value = false;
        m_value = new simple_glyph_t(m__io, this, m__root);
    }
}

ttf_t::glyf_t::~glyf_t() {
    _clean_up();
}

void ttf_t::glyf_t::_clean_up() {
    if (!n_value) {
        if (m_value) {
            delete m_value; m_value = 0;
        }
    }
}

ttf_t::glyf_t::simple_glyph_t::simple_glyph_t(kaitai::kstream* p__io, ttf_t::glyf_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_end_pts_of_contours = 0;
    m_flags = 0;
    f_point_count = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::glyf_t::simple_glyph_t::_read() {
    m_end_pts_of_contours = new std::vector<uint16_t>();
    const int l_end_pts_of_contours = _parent()->number_of_contours();
    for (int i = 0; i < l_end_pts_of_contours; i++) {
        m_end_pts_of_contours->push_back(m__io->read_u2be());
    }
    m_instruction_length = m__io->read_u2be();
    m_instructions = m__io->read_bytes(instruction_length());
    m_flags = new std::vector<flag_t*>();
    const int l_flags = point_count();
    for (int i = 0; i < l_flags; i++) {
        m_flags->push_back(new flag_t(m__io, this, m__root));
    }
}

ttf_t::glyf_t::simple_glyph_t::~simple_glyph_t() {
    _clean_up();
}

void ttf_t::glyf_t::simple_glyph_t::_clean_up() {
    if (m_end_pts_of_contours) {
        delete m_end_pts_of_contours; m_end_pts_of_contours = 0;
    }
    if (m_flags) {
        for (std::vector<flag_t*>::iterator it = m_flags->begin(); it != m_flags->end(); ++it) {
            delete *it;
        }
        delete m_flags; m_flags = 0;
    }
}

ttf_t::glyf_t::simple_glyph_t::flag_t::flag_t(kaitai::kstream* p__io, ttf_t::glyf_t::simple_glyph_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::glyf_t::simple_glyph_t::flag_t::_read() {
    m_reserved = m__io->read_bits_int_be(2);
    m_y_is_same = m__io->read_bits_int_be(1);
    m_x_is_same = m__io->read_bits_int_be(1);
    m_repeat = m__io->read_bits_int_be(1);
    m_y_short_vector = m__io->read_bits_int_be(1);
    m_x_short_vector = m__io->read_bits_int_be(1);
    m_on_curve = m__io->read_bits_int_be(1);
    m__io->align_to_byte();
    n_repeat_value = true;
    if (repeat()) {
        n_repeat_value = false;
        m_repeat_value = m__io->read_u1();
    }
}

ttf_t::glyf_t::simple_glyph_t::flag_t::~flag_t() {
    _clean_up();
}

void ttf_t::glyf_t::simple_glyph_t::flag_t::_clean_up() {
    if (!n_repeat_value) {
    }
}

int32_t ttf_t::glyf_t::simple_glyph_t::point_count() {
    if (f_point_count)
        return m_point_count;
    m_point_count = (*std::max_element(end_pts_of_contours()->begin(), end_pts_of_contours()->end()) + 1);
    f_point_count = true;
    return m_point_count;
}

ttf_t::cvt_t::cvt_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_fwords = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cvt_t::_read() {
    m_fwords = new std::vector<int16_t>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_fwords->push_back(m__io->read_s2be());
            i++;
        }
    }
}

ttf_t::cvt_t::~cvt_t() {
    _clean_up();
}

void ttf_t::cvt_t::_clean_up() {
    if (m_fwords) {
        delete m_fwords; m_fwords = 0;
    }
}

ttf_t::maxp_t::maxp_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_table_version_number = 0;
    m_version10_body = 0;
    f_is_version10 = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::maxp_t::_read() {
    m_table_version_number = new fixed_t(m__io, this, m__root);
    m_num_glyphs = m__io->read_u2be();
    n_version10_body = true;
    if (is_version10()) {
        n_version10_body = false;
        m_version10_body = new maxp_version10_body_t(m__io, this, m__root);
    }
}

ttf_t::maxp_t::~maxp_t() {
    _clean_up();
}

void ttf_t::maxp_t::_clean_up() {
    if (m_table_version_number) {
        delete m_table_version_number; m_table_version_number = 0;
    }
    if (!n_version10_body) {
        if (m_version10_body) {
            delete m_version10_body; m_version10_body = 0;
        }
    }
}

bool ttf_t::maxp_t::is_version10() {
    if (f_is_version10)
        return m_is_version10;
    m_is_version10 =  ((table_version_number()->major() == 1) && (table_version_number()->minor() == 0)) ;
    f_is_version10 = true;
    return m_is_version10;
}

ttf_t::maxp_version10_body_t::maxp_version10_body_t(kaitai::kstream* p__io, ttf_t::maxp_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::maxp_version10_body_t::_read() {
    m_max_points = m__io->read_u2be();
    m_max_contours = m__io->read_u2be();
    m_max_composite_points = m__io->read_u2be();
    m_max_composite_contours = m__io->read_u2be();
    m_max_zones = m__io->read_u2be();
    m_max_twilight_points = m__io->read_u2be();
    m_max_storage = m__io->read_u2be();
    m_max_function_defs = m__io->read_u2be();
    m_max_instruction_defs = m__io->read_u2be();
    m_max_stack_elements = m__io->read_u2be();
    m_max_size_of_instructions = m__io->read_u2be();
    m_max_component_elements = m__io->read_u2be();
    m_max_component_depth = m__io->read_u2be();
}

ttf_t::maxp_version10_body_t::~maxp_version10_body_t() {
    _clean_up();
}

void ttf_t::maxp_version10_body_t::_clean_up() {
}

ttf_t::offset_table_t::offset_table_t(kaitai::kstream* p__io, ttf_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_sfnt_version = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::offset_table_t::_read() {
    m_sfnt_version = new fixed_t(m__io, this, m__root);
    m_num_tables = m__io->read_u2be();
    m_search_range = m__io->read_u2be();
    m_entry_selector = m__io->read_u2be();
    m_range_shift = m__io->read_u2be();
}

ttf_t::offset_table_t::~offset_table_t() {
    _clean_up();
}

void ttf_t::offset_table_t::_clean_up() {
    if (m_sfnt_version) {
        delete m_sfnt_version; m_sfnt_version = 0;
    }
}

ttf_t::cmap_t::cmap_t(kaitai::kstream* p__io, ttf_t::dir_table_entry_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_tables = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::_read() {
    m_version_number = m__io->read_u2be();
    m_number_of_encoding_tables = m__io->read_u2be();
    m_tables = new std::vector<subtable_header_t*>();
    const int l_tables = number_of_encoding_tables();
    for (int i = 0; i < l_tables; i++) {
        m_tables->push_back(new subtable_header_t(m__io, this, m__root));
    }
}

ttf_t::cmap_t::~cmap_t() {
    _clean_up();
}

void ttf_t::cmap_t::_clean_up() {
    if (m_tables) {
        for (std::vector<subtable_header_t*>::iterator it = m_tables->begin(); it != m_tables->end(); ++it) {
            delete *it;
        }
        delete m_tables; m_tables = 0;
    }
}

ttf_t::cmap_t::subtable_header_t::subtable_header_t(kaitai::kstream* p__io, ttf_t::cmap_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_table = 0;
    f_table = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::subtable_header_t::_read() {
    m_platform_id = m__io->read_u2be();
    m_encoding_id = m__io->read_u2be();
    m_subtable_offset = m__io->read_u4be();
}

ttf_t::cmap_t::subtable_header_t::~subtable_header_t() {
    _clean_up();
}

void ttf_t::cmap_t::subtable_header_t::_clean_up() {
    if (f_table) {
        if (m_table) {
            delete m_table; m_table = 0;
        }
    }
}

ttf_t::cmap_t::subtable_t* ttf_t::cmap_t::subtable_header_t::table() {
    if (f_table)
        return m_table;
    kaitai::kstream *io = _parent()->_io();
    std::streampos _pos = io->pos();
    io->seek(subtable_offset());
    m_table = new subtable_t(io, this, m__root);
    io->seek(_pos);
    f_table = true;
    return m_table;
}

ttf_t::cmap_t::subtable_t::subtable_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_header_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_value = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::subtable_t::_read() {
    m_format = static_cast<ttf_t::cmap_t::subtable_t::subtable_format_t>(m__io->read_u2be());
    m_length = m__io->read_u2be();
    m_version = m__io->read_u2be();
    n_value = true;
    switch (format()) {
    case ttf_t::cmap_t::subtable_t::SUBTABLE_FORMAT_BYTE_ENCODING_TABLE: {
        n_value = false;
        m__raw_value = m__io->read_bytes((length() - 6));
        m__io__raw_value = new kaitai::kstream(m__raw_value);
        m_value = new byte_encoding_table_t(m__io__raw_value, this, m__root);
        break;
    }
    case ttf_t::cmap_t::subtable_t::SUBTABLE_FORMAT_SEGMENT_MAPPING_TO_DELTA_VALUES: {
        n_value = false;
        m__raw_value = m__io->read_bytes((length() - 6));
        m__io__raw_value = new kaitai::kstream(m__raw_value);
        m_value = new segment_mapping_to_delta_values_t(m__io__raw_value, this, m__root);
        break;
    }
    case ttf_t::cmap_t::subtable_t::SUBTABLE_FORMAT_HIGH_BYTE_MAPPING_THROUGH_TABLE: {
        n_value = false;
        m__raw_value = m__io->read_bytes((length() - 6));
        m__io__raw_value = new kaitai::kstream(m__raw_value);
        m_value = new high_byte_mapping_through_table_t(m__io__raw_value, this, m__root);
        break;
    }
    case ttf_t::cmap_t::subtable_t::SUBTABLE_FORMAT_TRIMMED_TABLE_MAPPING: {
        n_value = false;
        m__raw_value = m__io->read_bytes((length() - 6));
        m__io__raw_value = new kaitai::kstream(m__raw_value);
        m_value = new trimmed_table_mapping_t(m__io__raw_value, this, m__root);
        break;
    }
    default: {
        m__raw_value = m__io->read_bytes((length() - 6));
        break;
    }
    }
}

ttf_t::cmap_t::subtable_t::~subtable_t() {
    _clean_up();
}

void ttf_t::cmap_t::subtable_t::_clean_up() {
    if (!n_value) {
        if (m__io__raw_value) {
            delete m__io__raw_value; m__io__raw_value = 0;
        }
        if (m_value) {
            delete m_value; m_value = 0;
        }
    }
}

ttf_t::cmap_t::subtable_t::byte_encoding_table_t::byte_encoding_table_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::subtable_t::byte_encoding_table_t::_read() {
    m_glyph_id_array = m__io->read_bytes(256);
}

ttf_t::cmap_t::subtable_t::byte_encoding_table_t::~byte_encoding_table_t() {
    _clean_up();
}

void ttf_t::cmap_t::subtable_t::byte_encoding_table_t::_clean_up() {
}

ttf_t::cmap_t::subtable_t::high_byte_mapping_through_table_t::high_byte_mapping_through_table_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_sub_header_keys = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::subtable_t::high_byte_mapping_through_table_t::_read() {
    m_sub_header_keys = new std::vector<uint16_t>();
    const int l_sub_header_keys = 256;
    for (int i = 0; i < l_sub_header_keys; i++) {
        m_sub_header_keys->push_back(m__io->read_u2be());
    }
}

ttf_t::cmap_t::subtable_t::high_byte_mapping_through_table_t::~high_byte_mapping_through_table_t() {
    _clean_up();
}

void ttf_t::cmap_t::subtable_t::high_byte_mapping_through_table_t::_clean_up() {
    if (m_sub_header_keys) {
        delete m_sub_header_keys; m_sub_header_keys = 0;
    }
}

ttf_t::cmap_t::subtable_t::segment_mapping_to_delta_values_t::segment_mapping_to_delta_values_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_end_count = 0;
    m_start_count = 0;
    m_id_delta = 0;
    m_id_range_offset = 0;
    m_glyph_id_array = 0;
    f_seg_count = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::subtable_t::segment_mapping_to_delta_values_t::_read() {
    m_seg_count_x2 = m__io->read_u2be();
    m_search_range = m__io->read_u2be();
    m_entry_selector = m__io->read_u2be();
    m_range_shift = m__io->read_u2be();
    m_end_count = new std::vector<uint16_t>();
    const int l_end_count = seg_count();
    for (int i = 0; i < l_end_count; i++) {
        m_end_count->push_back(m__io->read_u2be());
    }
    m_reserved_pad = m__io->read_u2be();
    m_start_count = new std::vector<uint16_t>();
    const int l_start_count = seg_count();
    for (int i = 0; i < l_start_count; i++) {
        m_start_count->push_back(m__io->read_u2be());
    }
    m_id_delta = new std::vector<uint16_t>();
    const int l_id_delta = seg_count();
    for (int i = 0; i < l_id_delta; i++) {
        m_id_delta->push_back(m__io->read_u2be());
    }
    m_id_range_offset = new std::vector<uint16_t>();
    const int l_id_range_offset = seg_count();
    for (int i = 0; i < l_id_range_offset; i++) {
        m_id_range_offset->push_back(m__io->read_u2be());
    }
    m_glyph_id_array = new std::vector<uint16_t>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_glyph_id_array->push_back(m__io->read_u2be());
            i++;
        }
    }
}

ttf_t::cmap_t::subtable_t::segment_mapping_to_delta_values_t::~segment_mapping_to_delta_values_t() {
    _clean_up();
}

void ttf_t::cmap_t::subtable_t::segment_mapping_to_delta_values_t::_clean_up() {
    if (m_end_count) {
        delete m_end_count; m_end_count = 0;
    }
    if (m_start_count) {
        delete m_start_count; m_start_count = 0;
    }
    if (m_id_delta) {
        delete m_id_delta; m_id_delta = 0;
    }
    if (m_id_range_offset) {
        delete m_id_range_offset; m_id_range_offset = 0;
    }
    if (m_glyph_id_array) {
        delete m_glyph_id_array; m_glyph_id_array = 0;
    }
}

int32_t ttf_t::cmap_t::subtable_t::segment_mapping_to_delta_values_t::seg_count() {
    if (f_seg_count)
        return m_seg_count;
    m_seg_count = (seg_count_x2() / 2);
    f_seg_count = true;
    return m_seg_count;
}

ttf_t::cmap_t::subtable_t::trimmed_table_mapping_t::trimmed_table_mapping_t(kaitai::kstream* p__io, ttf_t::cmap_t::subtable_t* p__parent, ttf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_glyph_id_array = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void ttf_t::cmap_t::subtable_t::trimmed_table_mapping_t::_read() {
    m_first_code = m__io->read_u2be();
    m_entry_count = m__io->read_u2be();
    m_glyph_id_array = new std::vector<uint16_t>();
    const int l_glyph_id_array = entry_count();
    for (int i = 0; i < l_glyph_id_array; i++) {
        m_glyph_id_array->push_back(m__io->read_u2be());
    }
}

ttf_t::cmap_t::subtable_t::trimmed_table_mapping_t::~trimmed_table_mapping_t() {
    _clean_up();
}

void ttf_t::cmap_t::subtable_t::trimmed_table_mapping_t::_clean_up() {
    if (m_glyph_id_array) {
        delete m_glyph_id_array; m_glyph_id_array = 0;
    }
}