Portable Compiled Format (PCF) font: C++98/STL parsing library

Portable Compiled Format (PCF) font is a bitmap font format originating from X11 Window System. It matches BDF format (which is text-based) closely, but instead being binary and platform-independent (as opposed to previously used SNF binary format) due to introduced features to handle different endianness and bit order.

The overall composition of the format is straightforward: it's more or less classic directory of type-offset-size pointers, pointing to what PCF format calls "tables". Each table carries a certain piece of information related to the font (metadata properties, metrics, bitmaps, mapping of glyphs to characters, etc).

File extension

pcf

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of Portable Compiled Format (PCF) font 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.pcf", 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:
    pcf_font_t data(&ks);
    

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

data.magic() // => get magic

C++98/STL source code to parse Portable Compiled Format (PCF) font

pcf_font.h

#ifndef PCF_FONT_H_
#define PCF_FONT_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 "bytes_with_io.h"
#include <vector>

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

/**
 * Portable Compiled Format (PCF) font is a bitmap font format
 * originating from X11 Window System. It matches BDF format (which is
 * text-based) closely, but instead being binary and
 * platform-independent (as opposed to previously used SNF binary
 * format) due to introduced features to handle different endianness
 * and bit order.
 * 
 * The overall composition of the format is straightforward: it's more
 * or less classic directory of type-offset-size pointers, pointing to
 * what PCF format calls "tables". Each table carries a certain
 * piece of information related to the font (metadata properties,
 * metrics, bitmaps, mapping of glyphs to characters, etc).
 * \sa https://fontforge.org/docs/techref/pcf-format.html Source
 */

class pcf_font_t : public kaitai::kstruct {

public:
    class table_t;
    class format_t;

    enum types_t {
        TYPES_PROPERTIES = 1,
        TYPES_ACCELERATORS = 2,
        TYPES_METRICS = 4,
        TYPES_BITMAPS = 8,
        TYPES_INK_METRICS = 16,
        TYPES_BDF_ENCODINGS = 32,
        TYPES_SWIDTHS = 64,
        TYPES_GLYPH_NAMES = 128,
        TYPES_BDF_ACCELERATORS = 256
    };

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

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

public:
    ~pcf_font_t();

    /**
     * Table offers a offset + length pointer to a particular
     * table. "Type" of table references certain enum. Applications can
     * ignore enum values which they don't support.
     */

    class table_t : public kaitai::kstruct {

    public:
        class swidths_t;
        class properties_t;
        class bdf_encodings_t;
        class glyph_names_t;
        class bitmaps_t;

        table_t(kaitai::kstream* p__io, pcf_font_t* p__parent = 0, pcf_font_t* p__root = 0);

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

    public:
        ~table_t();

        /**
         * Table containing scalable widths of characters.
         * \sa https://fontforge.org/docs/techref/pcf-format.html#the-scalable-widths-table Source
         */

        class swidths_t : public kaitai::kstruct {

        public:

            swidths_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent = 0, pcf_font_t* p__root = 0);

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

        public:
            ~swidths_t();

        private:
            format_t* m_format;
            uint32_t m_num_glyphs;
            std::vector<uint32_t>* m_swidths;
            pcf_font_t* m__root;
            pcf_font_t::table_t* m__parent;

        public:
            format_t* format() const { return m_format; }
            uint32_t num_glyphs() const { return m_num_glyphs; }

            /**
             * The scalable width of a character is the width of the corresponding
             * PostScript character in em-units (1/1000ths of an em).
             */
            std::vector<uint32_t>* swidths() const { return m_swidths; }
            pcf_font_t* _root() const { return m__root; }
            pcf_font_t::table_t* _parent() const { return m__parent; }
        };

        /**
         * Array of properties (key-value pairs), used to convey different X11
         * settings of a font. Key is always an X font atom.
         * \sa https://fontforge.org/docs/techref/pcf-format.html#properties-table Source
         */

        class properties_t : public kaitai::kstruct {

        public:
            class prop_t;

            properties_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent = 0, pcf_font_t* p__root = 0);

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

        public:
            ~properties_t();

            /**
             * Property is a key-value pair, "key" being always a
             * string and "value" being either a string or a 32-bit
             * integer based on an additinal flag (`is_string`).
             * 
             * Simple offset-based mechanism is employed to keep this
             * type's sequence fixed-sized and thus have simple access
             * to property key/value by index.
             */

            class prop_t : public kaitai::kstruct {

            public:

                prop_t(kaitai::kstream* p__io, pcf_font_t::table_t::properties_t* p__parent = 0, pcf_font_t* p__root = 0);

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

            public:
                ~prop_t();

            private:
                bool f_name;
                std::string m_name;

            public:

                /**
                 * Name of the property addressed in the strings buffer.
                 */
                std::string name();

            private:
                bool f_str_value;
                std::string m_str_value;
                bool n_str_value;

            public:
                bool _is_null_str_value() { str_value(); return n_str_value; };

            private:

            public:

                /**
                 * Value of the property addressed in the strings
                 * buffer, if this is a string value.
                 */
                std::string str_value();

            private:
                bool f_int_value;
                uint32_t m_int_value;
                bool n_int_value;

            public:
                bool _is_null_int_value() { int_value(); return n_int_value; };

            private:

            public:

                /**
                 * Value of the property, if this is an integer value.
                 */
                uint32_t int_value();

            private:
                uint32_t m_ofs_name;
                uint8_t m_is_string;
                uint32_t m_value_or_ofs_value;
                pcf_font_t* m__root;
                pcf_font_t::table_t::properties_t* m__parent;

            public:

                /**
                 * Offset to name in the strings buffer.
                 */
                uint32_t ofs_name() const { return m_ofs_name; }

                /**
                 * Designates if value is an integer (zero) or a string (non-zero).
                 */
                uint8_t is_string() const { return m_is_string; }

                /**
                 * If the value is an integer (`is_string` is false),
                 * then it's stored here. If the value is a string
                 * (`is_string` is true), then it stores offset to the
                 * value in the strings buffer.
                 */
                uint32_t value_or_ofs_value() const { return m_value_or_ofs_value; }
                pcf_font_t* _root() const { return m__root; }
                pcf_font_t::table_t::properties_t* _parent() const { return m__parent; }
            };

        private:
            format_t* m_format;
            uint32_t m_num_props;
            std::vector<prop_t*>* m_props;
            std::string m_padding;
            uint32_t m_len_strings;
            bytes_with_io_t* m_strings;
            pcf_font_t* m__root;
            pcf_font_t::table_t* m__parent;
            std::string m__raw_strings;
            kaitai::kstream* m__io__raw_strings;

        public:
            format_t* format() const { return m_format; }
            uint32_t num_props() const { return m_num_props; }
            std::vector<prop_t*>* props() const { return m_props; }
            std::string padding() const { return m_padding; }
            uint32_t len_strings() const { return m_len_strings; }

            /**
             * Strings buffer. Never used directly, but instead is
             * addressed by offsets from the properties.
             */
            bytes_with_io_t* strings() const { return m_strings; }
            pcf_font_t* _root() const { return m__root; }
            pcf_font_t::table_t* _parent() const { return m__parent; }
            std::string _raw_strings() const { return m__raw_strings; }
            kaitai::kstream* _io__raw_strings() const { return m__io__raw_strings; }
        };

        /**
         * Table that allows mapping of character codes to glyphs present in the
         * font. Supports 1-byte and 2-byte character codes.
         * 
         * Note that this mapping is agnostic to character encoding itself - it
         * can represent ASCII, Unicode (ISO/IEC 10646), various single-byte
         * national encodings, etc. If application cares about it, normally
         * encoding will be specified in `properties` table, in the properties named
         * `CHARSET_REGISTRY` / `CHARSET_ENCODING`.
         * \sa https://fontforge.org/docs/techref/pcf-format.html#the-encoding-table Source
         */

        class bdf_encodings_t : public kaitai::kstruct {

        public:

            bdf_encodings_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent = 0, pcf_font_t* p__root = 0);

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

        public:
            ~bdf_encodings_t();

        private:
            format_t* m_format;
            uint16_t m_min_char_or_byte2;
            uint16_t m_max_char_or_byte2;
            uint16_t m_min_byte1;
            uint16_t m_max_byte1;
            uint16_t m_default_char;
            std::vector<uint16_t>* m_glyph_indexes;
            pcf_font_t* m__root;
            pcf_font_t::table_t* m__parent;

        public:
            format_t* format() const { return m_format; }
            uint16_t min_char_or_byte2() const { return m_min_char_or_byte2; }
            uint16_t max_char_or_byte2() const { return m_max_char_or_byte2; }
            uint16_t min_byte1() const { return m_min_byte1; }
            uint16_t max_byte1() const { return m_max_byte1; }
            uint16_t default_char() const { return m_default_char; }
            std::vector<uint16_t>* glyph_indexes() const { return m_glyph_indexes; }
            pcf_font_t* _root() const { return m__root; }
            pcf_font_t::table_t* _parent() const { return m__parent; }
        };

        /**
         * Table containing character names for every glyph.
         * \sa https://fontforge.org/docs/techref/pcf-format.html#the-glyph-names-table Source
         */

        class glyph_names_t : public kaitai::kstruct {

        public:
            class string_ref_t;

            glyph_names_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent = 0, pcf_font_t* p__root = 0);

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

        public:
            ~glyph_names_t();

            class string_ref_t : public kaitai::kstruct {

            public:

                string_ref_t(kaitai::kstream* p__io, pcf_font_t::table_t::glyph_names_t* p__parent = 0, pcf_font_t* p__root = 0);

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

            public:
                ~string_ref_t();

            private:
                bool f_value;
                std::string m_value;

            public:
                std::string value();

            private:
                uint32_t m_ofs_string;
                pcf_font_t* m__root;
                pcf_font_t::table_t::glyph_names_t* m__parent;

            public:
                uint32_t ofs_string() const { return m_ofs_string; }
                pcf_font_t* _root() const { return m__root; }
                pcf_font_t::table_t::glyph_names_t* _parent() const { return m__parent; }
            };

        private:
            format_t* m_format;
            uint32_t m_num_glyphs;
            std::vector<string_ref_t*>* m_names;
            uint32_t m_len_strings;
            bytes_with_io_t* m_strings;
            pcf_font_t* m__root;
            pcf_font_t::table_t* m__parent;
            std::string m__raw_strings;
            kaitai::kstream* m__io__raw_strings;

        public:
            format_t* format() const { return m_format; }
            uint32_t num_glyphs() const { return m_num_glyphs; }

            /**
             * Glyph names are represented as string references in strings buffer.
             */
            std::vector<string_ref_t*>* names() const { return m_names; }
            uint32_t len_strings() const { return m_len_strings; }

            /**
             * Strings buffer which contains all glyph names.
             */
            bytes_with_io_t* strings() const { return m_strings; }
            pcf_font_t* _root() const { return m__root; }
            pcf_font_t::table_t* _parent() const { return m__parent; }
            std::string _raw_strings() const { return m__raw_strings; }
            kaitai::kstream* _io__raw_strings() const { return m__io__raw_strings; }
        };

        /**
         * Table containing uncompressed glyph bitmaps.
         * \sa https://fontforge.org/docs/techref/pcf-format.html#the-bitmap-table Source
         */

        class bitmaps_t : public kaitai::kstruct {

        public:

            bitmaps_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent = 0, pcf_font_t* p__root = 0);

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

        public:
            ~bitmaps_t();

        private:
            format_t* m_format;
            uint32_t m_num_glyphs;
            std::vector<uint32_t>* m_offsets;
            std::vector<uint32_t>* m_bitmap_sizes;
            pcf_font_t* m__root;
            pcf_font_t::table_t* m__parent;

        public:
            format_t* format() const { return m_format; }
            uint32_t num_glyphs() const { return m_num_glyphs; }
            std::vector<uint32_t>* offsets() const { return m_offsets; }
            std::vector<uint32_t>* bitmap_sizes() const { return m_bitmap_sizes; }
            pcf_font_t* _root() const { return m__root; }
            pcf_font_t::table_t* _parent() const { return m__parent; }
        };

    private:
        bool f_body;
        kaitai::kstruct* m_body;
        bool n_body;

    public:
        bool _is_null_body() { body(); return n_body; };

    private:

    public:
        kaitai::kstruct* body();

    private:
        types_t m_type;
        format_t* m_format;
        uint32_t m_len_body;
        uint32_t m_ofs_body;
        pcf_font_t* m__root;
        pcf_font_t* m__parent;
        std::string m__raw_body;
        kaitai::kstream* m__io__raw_body;

    public:
        types_t type() const { return m_type; }
        format_t* format() const { return m_format; }
        uint32_t len_body() const { return m_len_body; }
        uint32_t ofs_body() const { return m_ofs_body; }
        pcf_font_t* _root() const { return m__root; }
        pcf_font_t* _parent() const { return m__parent; }
        std::string _raw_body() const { return m__raw_body; }
        kaitai::kstream* _io__raw_body() const { return m__io__raw_body; }
    };

    /**
     * Table format specifier, always 4 bytes. Original implementation treats
     * it as always little-endian and makes liberal use of bitmasking to parse
     * various parts of it.
     * 
     * TODO: this format specification recognizes endianness and bit
     * order format bits, but it does not really takes any parsing
     * decisions based on them.
     * \sa https://fontforge.org/docs/techref/pcf-format.html#file-header Source
     */

    class format_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~format_t();

    private:
        uint64_t m_padding1;
        uint64_t m_scan_unit_mask;
        bool m_is_most_significant_bit_first;
        bool m_is_big_endian;
        uint64_t m_glyph_pad_mask;
        uint8_t m_format;
        uint16_t m_padding;
        pcf_font_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        uint64_t padding1() const { return m_padding1; }
        uint64_t scan_unit_mask() const { return m_scan_unit_mask; }
        bool is_most_significant_bit_first() const { return m_is_most_significant_bit_first; }

        /**
         * If set, then all integers in the table are treated as big-endian
         */
        bool is_big_endian() const { return m_is_big_endian; }
        uint64_t glyph_pad_mask() const { return m_glyph_pad_mask; }
        uint8_t format() const { return m_format; }
        uint16_t padding() const { return m_padding; }
        pcf_font_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

private:
    std::string m_magic;
    uint32_t m_num_tables;
    std::vector<table_t*>* m_tables;
    pcf_font_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::string magic() const { return m_magic; }
    uint32_t num_tables() const { return m_num_tables; }
    std::vector<table_t*>* tables() const { return m_tables; }
    pcf_font_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // PCF_FONT_H_

pcf_font.cpp

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

#include "pcf_font.h"
#include "kaitai/exceptions.h"

pcf_font_t::pcf_font_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_tables = 0;

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

void pcf_font_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x01\x66\x63\x70", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x01\x66\x63\x70", 4), magic(), _io(), std::string("/seq/0"));
    }
    m_num_tables = m__io->read_u4le();
    m_tables = new std::vector<table_t*>();
    const int l_tables = num_tables();
    for (int i = 0; i < l_tables; i++) {
        m_tables->push_back(new table_t(m__io, this, m__root));
    }
}

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

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

pcf_font_t::table_t::table_t(kaitai::kstream* p__io, pcf_font_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m__io__raw_body = 0;
    f_body = false;

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

void pcf_font_t::table_t::_read() {
    m_type = static_cast<pcf_font_t::types_t>(m__io->read_u4le());
    m_format = new format_t(m__io, this, m__root);
    m_len_body = m__io->read_u4le();
    m_ofs_body = m__io->read_u4le();
}

pcf_font_t::table_t::~table_t() {
    _clean_up();
}

void pcf_font_t::table_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (f_body && !n_body) {
        if (m__io__raw_body) {
            delete m__io__raw_body; m__io__raw_body = 0;
        }
        if (m_body) {
            delete m_body; m_body = 0;
        }
    }
}

pcf_font_t::table_t::swidths_t::swidths_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m_swidths = 0;

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

void pcf_font_t::table_t::swidths_t::_read() {
    m_format = new format_t(m__io, this, m__root);
    m_num_glyphs = m__io->read_u4le();
    m_swidths = new std::vector<uint32_t>();
    const int l_swidths = num_glyphs();
    for (int i = 0; i < l_swidths; i++) {
        m_swidths->push_back(m__io->read_u4le());
    }
}

pcf_font_t::table_t::swidths_t::~swidths_t() {
    _clean_up();
}

void pcf_font_t::table_t::swidths_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (m_swidths) {
        delete m_swidths; m_swidths = 0;
    }
}

pcf_font_t::table_t::properties_t::properties_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m_props = 0;
    m_strings = 0;
    m__io__raw_strings = 0;

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

void pcf_font_t::table_t::properties_t::_read() {
    m_format = new format_t(m__io, this, m__root);
    m_num_props = m__io->read_u4le();
    m_props = new std::vector<prop_t*>();
    const int l_props = num_props();
    for (int i = 0; i < l_props; i++) {
        m_props->push_back(new prop_t(m__io, this, m__root));
    }
    m_padding = m__io->read_bytes((((num_props() & 3) == 0) ? (0) : ((4 - (num_props() & 3)))));
    m_len_strings = m__io->read_u4le();
    m__raw_strings = m__io->read_bytes(len_strings());
    m__io__raw_strings = new kaitai::kstream(m__raw_strings);
    m_strings = new bytes_with_io_t(m__io__raw_strings);
}

pcf_font_t::table_t::properties_t::~properties_t() {
    _clean_up();
}

void pcf_font_t::table_t::properties_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (m_props) {
        for (std::vector<prop_t*>::iterator it = m_props->begin(); it != m_props->end(); ++it) {
            delete *it;
        }
        delete m_props; m_props = 0;
    }
    if (m__io__raw_strings) {
        delete m__io__raw_strings; m__io__raw_strings = 0;
    }
    if (m_strings) {
        delete m_strings; m_strings = 0;
    }
}

pcf_font_t::table_t::properties_t::prop_t::prop_t(kaitai::kstream* p__io, pcf_font_t::table_t::properties_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_name = false;
    f_str_value = false;
    f_int_value = false;

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

void pcf_font_t::table_t::properties_t::prop_t::_read() {
    m_ofs_name = m__io->read_u4le();
    m_is_string = m__io->read_u1();
    m_value_or_ofs_value = m__io->read_u4le();
}

pcf_font_t::table_t::properties_t::prop_t::~prop_t() {
    _clean_up();
}

void pcf_font_t::table_t::properties_t::prop_t::_clean_up() {
    if (f_name) {
    }
    if (f_str_value && !n_str_value) {
    }
}

std::string pcf_font_t::table_t::properties_t::prop_t::name() {
    if (f_name)
        return m_name;
    kaitai::kstream *io = _parent()->strings()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_name());
    m_name = kaitai::kstream::bytes_to_str(io->read_bytes_term(0, false, true, true), std::string("UTF-8"));
    io->seek(_pos);
    f_name = true;
    return m_name;
}

std::string pcf_font_t::table_t::properties_t::prop_t::str_value() {
    if (f_str_value)
        return m_str_value;
    n_str_value = true;
    if (is_string() != 0) {
        n_str_value = false;
        kaitai::kstream *io = _parent()->strings()->_io();
        std::streampos _pos = io->pos();
        io->seek(value_or_ofs_value());
        m_str_value = kaitai::kstream::bytes_to_str(io->read_bytes_term(0, false, true, true), std::string("UTF-8"));
        io->seek(_pos);
        f_str_value = true;
    }
    return m_str_value;
}

uint32_t pcf_font_t::table_t::properties_t::prop_t::int_value() {
    if (f_int_value)
        return m_int_value;
    n_int_value = true;
    if (is_string() == 0) {
        n_int_value = false;
        m_int_value = value_or_ofs_value();
    }
    f_int_value = true;
    return m_int_value;
}

pcf_font_t::table_t::bdf_encodings_t::bdf_encodings_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m_glyph_indexes = 0;

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

void pcf_font_t::table_t::bdf_encodings_t::_read() {
    m_format = new format_t(m__io, this, m__root);
    m_min_char_or_byte2 = m__io->read_u2le();
    m_max_char_or_byte2 = m__io->read_u2le();
    m_min_byte1 = m__io->read_u2le();
    m_max_byte1 = m__io->read_u2le();
    m_default_char = m__io->read_u2le();
    m_glyph_indexes = new std::vector<uint16_t>();
    const int l_glyph_indexes = (((max_char_or_byte2() - min_char_or_byte2()) + 1) * ((max_byte1() - min_byte1()) + 1));
    for (int i = 0; i < l_glyph_indexes; i++) {
        m_glyph_indexes->push_back(m__io->read_u2le());
    }
}

pcf_font_t::table_t::bdf_encodings_t::~bdf_encodings_t() {
    _clean_up();
}

void pcf_font_t::table_t::bdf_encodings_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (m_glyph_indexes) {
        delete m_glyph_indexes; m_glyph_indexes = 0;
    }
}

pcf_font_t::table_t::glyph_names_t::glyph_names_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m_names = 0;
    m_strings = 0;
    m__io__raw_strings = 0;

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

void pcf_font_t::table_t::glyph_names_t::_read() {
    m_format = new format_t(m__io, this, m__root);
    m_num_glyphs = m__io->read_u4le();
    m_names = new std::vector<string_ref_t*>();
    const int l_names = num_glyphs();
    for (int i = 0; i < l_names; i++) {
        m_names->push_back(new string_ref_t(m__io, this, m__root));
    }
    m_len_strings = m__io->read_u4le();
    m__raw_strings = m__io->read_bytes(len_strings());
    m__io__raw_strings = new kaitai::kstream(m__raw_strings);
    m_strings = new bytes_with_io_t(m__io__raw_strings);
}

pcf_font_t::table_t::glyph_names_t::~glyph_names_t() {
    _clean_up();
}

void pcf_font_t::table_t::glyph_names_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (m_names) {
        for (std::vector<string_ref_t*>::iterator it = m_names->begin(); it != m_names->end(); ++it) {
            delete *it;
        }
        delete m_names; m_names = 0;
    }
    if (m__io__raw_strings) {
        delete m__io__raw_strings; m__io__raw_strings = 0;
    }
    if (m_strings) {
        delete m_strings; m_strings = 0;
    }
}

pcf_font_t::table_t::glyph_names_t::string_ref_t::string_ref_t(kaitai::kstream* p__io, pcf_font_t::table_t::glyph_names_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_value = false;

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

void pcf_font_t::table_t::glyph_names_t::string_ref_t::_read() {
    m_ofs_string = m__io->read_u4le();
}

pcf_font_t::table_t::glyph_names_t::string_ref_t::~string_ref_t() {
    _clean_up();
}

void pcf_font_t::table_t::glyph_names_t::string_ref_t::_clean_up() {
    if (f_value) {
    }
}

std::string pcf_font_t::table_t::glyph_names_t::string_ref_t::value() {
    if (f_value)
        return m_value;
    kaitai::kstream *io = _parent()->strings()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_string());
    m_value = kaitai::kstream::bytes_to_str(io->read_bytes_term(0, false, true, true), std::string("UTF-8"));
    io->seek(_pos);
    f_value = true;
    return m_value;
}

pcf_font_t::table_t::bitmaps_t::bitmaps_t(kaitai::kstream* p__io, pcf_font_t::table_t* p__parent, pcf_font_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_format = 0;
    m_offsets = 0;
    m_bitmap_sizes = 0;

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

void pcf_font_t::table_t::bitmaps_t::_read() {
    m_format = new format_t(m__io, this, m__root);
    m_num_glyphs = m__io->read_u4le();
    m_offsets = new std::vector<uint32_t>();
    const int l_offsets = num_glyphs();
    for (int i = 0; i < l_offsets; i++) {
        m_offsets->push_back(m__io->read_u4le());
    }
    m_bitmap_sizes = new std::vector<uint32_t>();
    const int l_bitmap_sizes = 4;
    for (int i = 0; i < l_bitmap_sizes; i++) {
        m_bitmap_sizes->push_back(m__io->read_u4le());
    }
}

pcf_font_t::table_t::bitmaps_t::~bitmaps_t() {
    _clean_up();
}

void pcf_font_t::table_t::bitmaps_t::_clean_up() {
    if (m_format) {
        delete m_format; m_format = 0;
    }
    if (m_offsets) {
        delete m_offsets; m_offsets = 0;
    }
    if (m_bitmap_sizes) {
        delete m_bitmap_sizes; m_bitmap_sizes = 0;
    }
}

kaitai::kstruct* pcf_font_t::table_t::body() {
    if (f_body)
        return m_body;
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_body());
    n_body = true;
    switch (type()) {
    case pcf_font_t::TYPES_PROPERTIES: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new properties_t(m__io__raw_body, this, m__root);
        break;
    }
    case pcf_font_t::TYPES_BDF_ENCODINGS: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new bdf_encodings_t(m__io__raw_body, this, m__root);
        break;
    }
    case pcf_font_t::TYPES_SWIDTHS: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new swidths_t(m__io__raw_body, this, m__root);
        break;
    }
    case pcf_font_t::TYPES_GLYPH_NAMES: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new glyph_names_t(m__io__raw_body, this, m__root);
        break;
    }
    case pcf_font_t::TYPES_BITMAPS: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new bitmaps_t(m__io__raw_body, this, m__root);
        break;
    }
    default: {
        m__raw_body = m__io->read_bytes(len_body());
        break;
    }
    }
    m__io->seek(_pos);
    f_body = true;
    return m_body;
}

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

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

void pcf_font_t::format_t::_read() {
    m_padding1 = m__io->read_bits_int_be(2);
    m_scan_unit_mask = m__io->read_bits_int_be(2);
    m_is_most_significant_bit_first = m__io->read_bits_int_be(1);
    m_is_big_endian = m__io->read_bits_int_be(1);
    m_glyph_pad_mask = m__io->read_bits_int_be(2);
    m__io->align_to_byte();
    m_format = m__io->read_u1();
    m_padding = m__io->read_u2le();
}

pcf_font_t::format_t::~format_t() {
    _clean_up();
}

void pcf_font_t::format_t::_clean_up() {
}