GIF (Graphics Interchange Format) image file: C++11/STL parsing library

GIF (Graphics Interchange Format) is an image file format, developed in 1987. It became popular in 1990s as one of the main image formats used in World Wide Web.

GIF format allows encoding of palette-based images up to 256 colors (each of the colors can be chosen from a 24-bit RGB colorspace). Image data stream uses LZW (Lempel-Ziv-Welch) lossless compression.

Over the years, several version of the format were published and several extensions to it were made, namely, a popular Netscape extension that allows to store several images in one file, switching between them, which produces crude form of animation.

Structurally, format consists of several mandatory headers and then a stream of blocks follows. Blocks can carry additional metainformation or image data.

This page hosts a formal specification of GIF (Graphics Interchange Format) image 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++11/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.gif", 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:
    gif_t data(&ks);
    

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

data.hdr() // => get hdr

C++11/STL source code to parse GIF (Graphics Interchange Format) image file

gif.h

#pragma once

// 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 <memory>
#include <vector>

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

/**
 * GIF (Graphics Interchange Format) is an image file format, developed
 * in 1987. It became popular in 1990s as one of the main image formats
 * used in World Wide Web.
 * 
 * GIF format allows encoding of palette-based images up to 256 colors
 * (each of the colors can be chosen from a 24-bit RGB
 * colorspace). Image data stream uses LZW (Lempel-Ziv-Welch) lossless
 * compression.
 * 
 * Over the years, several version of the format were published and
 * several extensions to it were made, namely, a popular Netscape
 * extension that allows to store several images in one file, switching
 * between them, which produces crude form of animation.
 * 
 * Structurally, format consists of several mandatory headers and then
 * a stream of blocks follows. Blocks can carry additional
 * metainformation or image data.
 */

class gif_t : public kaitai::kstruct {

public:
    class image_data_t;
    class color_table_entry_t;
    class logical_screen_descriptor_struct_t;
    class local_image_descriptor_t;
    class block_t;
    class color_table_t;
    class header_t;
    class ext_graphic_control_t;
    class subblock_t;
    class application_id_t;
    class ext_application_t;
    class subblocks_t;
    class extension_t;

    enum block_type_t {
        BLOCK_TYPE_EXTENSION = 33,
        BLOCK_TYPE_LOCAL_IMAGE_DESCRIPTOR = 44,
        BLOCK_TYPE_END_OF_FILE = 59
    };

    enum extension_label_t {
        EXTENSION_LABEL_GRAPHIC_CONTROL = 249,
        EXTENSION_LABEL_COMMENT = 254,
        EXTENSION_LABEL_APPLICATION = 255
    };

    gif_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, gif_t* p__root = nullptr);

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

public:
    ~gif_t();

    /**
     * \sa https://www.w3.org/Graphics/GIF/spec-gif89a.txt - section 22
     */

    class image_data_t : public kaitai::kstruct {

    public:

        image_data_t(kaitai::kstream* p__io, gif_t::local_image_descriptor_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~image_data_t();

    private:
        uint8_t m_lzw_min_code_size;
        std::unique_ptr<subblocks_t> m_subblocks;
        gif_t* m__root;
        gif_t::local_image_descriptor_t* m__parent;

    public:
        uint8_t lzw_min_code_size() const { return m_lzw_min_code_size; }
        subblocks_t* subblocks() const { return m_subblocks.get(); }
        gif_t* _root() const { return m__root; }
        gif_t::local_image_descriptor_t* _parent() const { return m__parent; }
    };

    class color_table_entry_t : public kaitai::kstruct {

    public:

        color_table_entry_t(kaitai::kstream* p__io, gif_t::color_table_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~color_table_entry_t();

    private:
        uint8_t m_red;
        uint8_t m_green;
        uint8_t m_blue;
        gif_t* m__root;
        gif_t::color_table_t* m__parent;

    public:
        uint8_t red() const { return m_red; }
        uint8_t green() const { return m_green; }
        uint8_t blue() const { return m_blue; }
        gif_t* _root() const { return m__root; }
        gif_t::color_table_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://www.w3.org/Graphics/GIF/spec-gif89a.txt - section 18
     */

    class logical_screen_descriptor_struct_t : public kaitai::kstruct {

    public:

        logical_screen_descriptor_struct_t(kaitai::kstream* p__io, gif_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~logical_screen_descriptor_struct_t();

    private:
        bool f_has_color_table;
        bool m_has_color_table;

    public:
        bool has_color_table();

    private:
        bool f_color_table_size;
        int32_t m_color_table_size;

    public:
        int32_t color_table_size();

    private:
        uint16_t m_screen_width;
        uint16_t m_screen_height;
        uint8_t m_flags;
        uint8_t m_bg_color_index;
        uint8_t m_pixel_aspect_ratio;
        gif_t* m__root;
        gif_t* m__parent;

    public:
        uint16_t screen_width() const { return m_screen_width; }
        uint16_t screen_height() const { return m_screen_height; }
        uint8_t flags() const { return m_flags; }
        uint8_t bg_color_index() const { return m_bg_color_index; }
        uint8_t pixel_aspect_ratio() const { return m_pixel_aspect_ratio; }
        gif_t* _root() const { return m__root; }
        gif_t* _parent() const { return m__parent; }
    };

    class local_image_descriptor_t : public kaitai::kstruct {

    public:

        local_image_descriptor_t(kaitai::kstream* p__io, gif_t::block_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~local_image_descriptor_t();

    private:
        bool f_has_color_table;
        bool m_has_color_table;

    public:
        bool has_color_table();

    private:
        bool f_has_interlace;
        bool m_has_interlace;

    public:
        bool has_interlace();

    private:
        bool f_has_sorted_color_table;
        bool m_has_sorted_color_table;

    public:
        bool has_sorted_color_table();

    private:
        bool f_color_table_size;
        int32_t m_color_table_size;

    public:
        int32_t color_table_size();

    private:
        uint16_t m_left;
        uint16_t m_top;
        uint16_t m_width;
        uint16_t m_height;
        uint8_t m_flags;
        std::unique_ptr<color_table_t> m_local_color_table;
        bool n_local_color_table;

    public:
        bool _is_null_local_color_table() { local_color_table(); return n_local_color_table; };

    private:
        std::unique_ptr<image_data_t> m_image_data;
        gif_t* m__root;
        gif_t::block_t* m__parent;
        std::string m__raw_local_color_table;
        bool n__raw_local_color_table;

    public:
        bool _is_null__raw_local_color_table() { _raw_local_color_table(); return n__raw_local_color_table; };

    private:
        std::unique_ptr<kaitai::kstream> m__io__raw_local_color_table;

    public:
        uint16_t left() const { return m_left; }
        uint16_t top() const { return m_top; }
        uint16_t width() const { return m_width; }
        uint16_t height() const { return m_height; }
        uint8_t flags() const { return m_flags; }
        color_table_t* local_color_table() const { return m_local_color_table.get(); }
        image_data_t* image_data() const { return m_image_data.get(); }
        gif_t* _root() const { return m__root; }
        gif_t::block_t* _parent() const { return m__parent; }
        std::string _raw_local_color_table() const { return m__raw_local_color_table; }
        kaitai::kstream* _io__raw_local_color_table() const { return m__io__raw_local_color_table.get(); }
    };

    class block_t : public kaitai::kstruct {

    public:

        block_t(kaitai::kstream* p__io, gif_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~block_t();

    private:
        block_type_t m_block_type;
        std::unique_ptr<kaitai::kstruct> m_body;
        bool n_body;

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

    private:
        gif_t* m__root;
        gif_t* m__parent;

    public:
        block_type_t block_type() const { return m_block_type; }
        kaitai::kstruct* body() const { return m_body.get(); }
        gif_t* _root() const { return m__root; }
        gif_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://www.w3.org/Graphics/GIF/spec-gif89a.txt - section 19
     */

    class color_table_t : public kaitai::kstruct {

    public:

        color_table_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~color_table_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<color_table_entry_t>>> m_entries;
        gif_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        std::vector<std::unique_ptr<color_table_entry_t>>* entries() const { return m_entries.get(); }
        gif_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    /**
     * \sa https://www.w3.org/Graphics/GIF/spec-gif89a.txt - section 17
     */

    class header_t : public kaitai::kstruct {

    public:

        header_t(kaitai::kstream* p__io, gif_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~header_t();

    private:
        std::string m_magic;
        std::string m_version;
        gif_t* m__root;
        gif_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        std::string version() const { return m_version; }
        gif_t* _root() const { return m__root; }
        gif_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://www.w3.org/Graphics/GIF/spec-gif89a.txt - section 23
     */

    class ext_graphic_control_t : public kaitai::kstruct {

    public:

        ext_graphic_control_t(kaitai::kstream* p__io, gif_t::extension_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~ext_graphic_control_t();

    private:
        bool f_transparent_color_flag;
        bool m_transparent_color_flag;

    public:
        bool transparent_color_flag();

    private:
        bool f_user_input_flag;
        bool m_user_input_flag;

    public:
        bool user_input_flag();

    private:
        std::string m_block_size;
        uint8_t m_flags;
        uint16_t m_delay_time;
        uint8_t m_transparent_idx;
        std::string m_terminator;
        gif_t* m__root;
        gif_t::extension_t* m__parent;

    public:
        std::string block_size() const { return m_block_size; }
        uint8_t flags() const { return m_flags; }
        uint16_t delay_time() const { return m_delay_time; }
        uint8_t transparent_idx() const { return m_transparent_idx; }
        std::string terminator() const { return m_terminator; }
        gif_t* _root() const { return m__root; }
        gif_t::extension_t* _parent() const { return m__parent; }
    };

    class subblock_t : public kaitai::kstruct {

    public:

        subblock_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~subblock_t();

    private:
        uint8_t m_len_bytes;
        std::string m_bytes;
        gif_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        uint8_t len_bytes() const { return m_len_bytes; }
        std::string bytes() const { return m_bytes; }
        gif_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class application_id_t : public kaitai::kstruct {

    public:

        application_id_t(kaitai::kstream* p__io, gif_t::ext_application_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~application_id_t();

    private:
        uint8_t m_len_bytes;
        std::string m_application_identifier;
        std::string m_application_auth_code;
        gif_t* m__root;
        gif_t::ext_application_t* m__parent;

    public:
        uint8_t len_bytes() const { return m_len_bytes; }
        std::string application_identifier() const { return m_application_identifier; }
        std::string application_auth_code() const { return m_application_auth_code; }
        gif_t* _root() const { return m__root; }
        gif_t::ext_application_t* _parent() const { return m__parent; }
    };

    class ext_application_t : public kaitai::kstruct {

    public:

        ext_application_t(kaitai::kstream* p__io, gif_t::extension_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~ext_application_t();

    private:
        std::unique_ptr<application_id_t> m_application_id;
        std::unique_ptr<std::vector<std::unique_ptr<subblock_t>>> m_subblocks;
        gif_t* m__root;
        gif_t::extension_t* m__parent;

    public:
        application_id_t* application_id() const { return m_application_id.get(); }
        std::vector<std::unique_ptr<subblock_t>>* subblocks() const { return m_subblocks.get(); }
        gif_t* _root() const { return m__root; }
        gif_t::extension_t* _parent() const { return m__parent; }
    };

    class subblocks_t : public kaitai::kstruct {

    public:

        subblocks_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~subblocks_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<subblock_t>>> m_entries;
        gif_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        std::vector<std::unique_ptr<subblock_t>>* entries() const { return m_entries.get(); }
        gif_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class extension_t : public kaitai::kstruct {

    public:

        extension_t(kaitai::kstream* p__io, gif_t::block_t* p__parent = nullptr, gif_t* p__root = nullptr);

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

    public:
        ~extension_t();

    private:
        extension_label_t m_label;
        std::unique_ptr<kaitai::kstruct> m_body;
        gif_t* m__root;
        gif_t::block_t* m__parent;

    public:
        extension_label_t label() const { return m_label; }
        kaitai::kstruct* body() const { return m_body.get(); }
        gif_t* _root() const { return m__root; }
        gif_t::block_t* _parent() const { return m__parent; }
    };

private:
    std::unique_ptr<header_t> m_hdr;
    std::unique_ptr<logical_screen_descriptor_struct_t> m_logical_screen_descriptor;
    std::unique_ptr<color_table_t> m_global_color_table;
    bool n_global_color_table;

public:
    bool _is_null_global_color_table() { global_color_table(); return n_global_color_table; };

private:
    std::unique_ptr<std::vector<std::unique_ptr<block_t>>> m_blocks;
    gif_t* m__root;
    kaitai::kstruct* m__parent;
    std::string m__raw_global_color_table;
    bool n__raw_global_color_table;

public:
    bool _is_null__raw_global_color_table() { _raw_global_color_table(); return n__raw_global_color_table; };

private:
    std::unique_ptr<kaitai::kstream> m__io__raw_global_color_table;

public:
    header_t* hdr() const { return m_hdr.get(); }
    logical_screen_descriptor_struct_t* logical_screen_descriptor() const { return m_logical_screen_descriptor.get(); }

    /**
     * \sa https://www.w3.org/Graphics/GIF/spec-gif89a.txt - section 18
     */
    color_table_t* global_color_table() const { return m_global_color_table.get(); }
    std::vector<std::unique_ptr<block_t>>* blocks() const { return m_blocks.get(); }
    gif_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::string _raw_global_color_table() const { return m__raw_global_color_table; }
    kaitai::kstream* _io__raw_global_color_table() const { return m__io__raw_global_color_table.get(); }
};

gif.cpp

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

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

gif_t::gif_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_hdr = nullptr;
    m_logical_screen_descriptor = nullptr;
    m_global_color_table = nullptr;
    m__io__raw_global_color_table = nullptr;
    m_blocks = nullptr;
    _read();
}

void gif_t::_read() {
    m_hdr = std::unique_ptr<header_t>(new header_t(m__io, this, m__root));
    m_logical_screen_descriptor = std::unique_ptr<logical_screen_descriptor_struct_t>(new logical_screen_descriptor_struct_t(m__io, this, m__root));
    n_global_color_table = true;
    if (logical_screen_descriptor()->has_color_table()) {
        n_global_color_table = false;
        m__raw_global_color_table = m__io->read_bytes((logical_screen_descriptor()->color_table_size() * 3));
        m__io__raw_global_color_table = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_global_color_table));
        m_global_color_table = std::unique_ptr<color_table_t>(new color_table_t(m__io__raw_global_color_table.get(), this, m__root));
    }
    m_blocks = std::unique_ptr<std::vector<std::unique_ptr<block_t>>>(new std::vector<std::unique_ptr<block_t>>());
    {
        int i = 0;
        block_t* _;
        do {
            _ = new block_t(m__io, this, m__root);
            m_blocks->push_back(std::move(std::unique_ptr<block_t>(_)));
            i++;
        } while (!( ((_io()->is_eof()) || (_->block_type() == gif_t::BLOCK_TYPE_END_OF_FILE)) ));
    }
}

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

void gif_t::_clean_up() {
    if (!n_global_color_table) {
    }
}

gif_t::image_data_t::image_data_t(kaitai::kstream* p__io, gif_t::local_image_descriptor_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_subblocks = nullptr;
    _read();
}

void gif_t::image_data_t::_read() {
    m_lzw_min_code_size = m__io->read_u1();
    m_subblocks = std::unique_ptr<subblocks_t>(new subblocks_t(m__io, this, m__root));
}

gif_t::image_data_t::~image_data_t() {
    _clean_up();
}

void gif_t::image_data_t::_clean_up() {
}

gif_t::color_table_entry_t::color_table_entry_t(kaitai::kstream* p__io, gif_t::color_table_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gif_t::color_table_entry_t::_read() {
    m_red = m__io->read_u1();
    m_green = m__io->read_u1();
    m_blue = m__io->read_u1();
}

gif_t::color_table_entry_t::~color_table_entry_t() {
    _clean_up();
}

void gif_t::color_table_entry_t::_clean_up() {
}

gif_t::logical_screen_descriptor_struct_t::logical_screen_descriptor_struct_t(kaitai::kstream* p__io, gif_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_has_color_table = false;
    f_color_table_size = false;
    _read();
}

void gif_t::logical_screen_descriptor_struct_t::_read() {
    m_screen_width = m__io->read_u2le();
    m_screen_height = m__io->read_u2le();
    m_flags = m__io->read_u1();
    m_bg_color_index = m__io->read_u1();
    m_pixel_aspect_ratio = m__io->read_u1();
}

gif_t::logical_screen_descriptor_struct_t::~logical_screen_descriptor_struct_t() {
    _clean_up();
}

void gif_t::logical_screen_descriptor_struct_t::_clean_up() {
}

bool gif_t::logical_screen_descriptor_struct_t::has_color_table() {
    if (f_has_color_table)
        return m_has_color_table;
    m_has_color_table = (flags() & 128) != 0;
    f_has_color_table = true;
    return m_has_color_table;
}

int32_t gif_t::logical_screen_descriptor_struct_t::color_table_size() {
    if (f_color_table_size)
        return m_color_table_size;
    m_color_table_size = (2 << (flags() & 7));
    f_color_table_size = true;
    return m_color_table_size;
}

gif_t::local_image_descriptor_t::local_image_descriptor_t(kaitai::kstream* p__io, gif_t::block_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_local_color_table = nullptr;
    m__io__raw_local_color_table = nullptr;
    m_image_data = nullptr;
    f_has_color_table = false;
    f_has_interlace = false;
    f_has_sorted_color_table = false;
    f_color_table_size = false;
    _read();
}

void gif_t::local_image_descriptor_t::_read() {
    m_left = m__io->read_u2le();
    m_top = m__io->read_u2le();
    m_width = m__io->read_u2le();
    m_height = m__io->read_u2le();
    m_flags = m__io->read_u1();
    n_local_color_table = true;
    if (has_color_table()) {
        n_local_color_table = false;
        m__raw_local_color_table = m__io->read_bytes((color_table_size() * 3));
        m__io__raw_local_color_table = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_local_color_table));
        m_local_color_table = std::unique_ptr<color_table_t>(new color_table_t(m__io__raw_local_color_table.get(), this, m__root));
    }
    m_image_data = std::unique_ptr<image_data_t>(new image_data_t(m__io, this, m__root));
}

gif_t::local_image_descriptor_t::~local_image_descriptor_t() {
    _clean_up();
}

void gif_t::local_image_descriptor_t::_clean_up() {
    if (!n_local_color_table) {
    }
}

bool gif_t::local_image_descriptor_t::has_color_table() {
    if (f_has_color_table)
        return m_has_color_table;
    m_has_color_table = (flags() & 128) != 0;
    f_has_color_table = true;
    return m_has_color_table;
}

bool gif_t::local_image_descriptor_t::has_interlace() {
    if (f_has_interlace)
        return m_has_interlace;
    m_has_interlace = (flags() & 64) != 0;
    f_has_interlace = true;
    return m_has_interlace;
}

bool gif_t::local_image_descriptor_t::has_sorted_color_table() {
    if (f_has_sorted_color_table)
        return m_has_sorted_color_table;
    m_has_sorted_color_table = (flags() & 32) != 0;
    f_has_sorted_color_table = true;
    return m_has_sorted_color_table;
}

int32_t gif_t::local_image_descriptor_t::color_table_size() {
    if (f_color_table_size)
        return m_color_table_size;
    m_color_table_size = (2 << (flags() & 7));
    f_color_table_size = true;
    return m_color_table_size;
}

gif_t::block_t::block_t(kaitai::kstream* p__io, gif_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gif_t::block_t::_read() {
    m_block_type = static_cast<gif_t::block_type_t>(m__io->read_u1());
    n_body = true;
    switch (block_type()) {
    case gif_t::BLOCK_TYPE_EXTENSION: {
        n_body = false;
        m_body = std::unique_ptr<extension_t>(new extension_t(m__io, this, m__root));
        break;
    }
    case gif_t::BLOCK_TYPE_LOCAL_IMAGE_DESCRIPTOR: {
        n_body = false;
        m_body = std::unique_ptr<local_image_descriptor_t>(new local_image_descriptor_t(m__io, this, m__root));
        break;
    }
    }
}

gif_t::block_t::~block_t() {
    _clean_up();
}

void gif_t::block_t::_clean_up() {
    if (!n_body) {
    }
}

gif_t::color_table_t::color_table_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void gif_t::color_table_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<color_table_entry_t>>>(new std::vector<std::unique_ptr<color_table_entry_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<color_table_entry_t>(new color_table_entry_t(m__io, this, m__root))));
            i++;
        }
    }
}

gif_t::color_table_t::~color_table_t() {
    _clean_up();
}

void gif_t::color_table_t::_clean_up() {
}

gif_t::header_t::header_t(kaitai::kstream* p__io, gif_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gif_t::header_t::_read() {
    m_magic = m__io->read_bytes(3);
    if (!(magic() == std::string("\x47\x49\x46", 3))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x47\x49\x46", 3), magic(), _io(), std::string("/types/header/seq/0"));
    }
    m_version = kaitai::kstream::bytes_to_str(m__io->read_bytes(3), std::string("ASCII"));
}

gif_t::header_t::~header_t() {
    _clean_up();
}

void gif_t::header_t::_clean_up() {
}

gif_t::ext_graphic_control_t::ext_graphic_control_t(kaitai::kstream* p__io, gif_t::extension_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_transparent_color_flag = false;
    f_user_input_flag = false;
    _read();
}

void gif_t::ext_graphic_control_t::_read() {
    m_block_size = m__io->read_bytes(1);
    if (!(block_size() == std::string("\x04", 1))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x04", 1), block_size(), _io(), std::string("/types/ext_graphic_control/seq/0"));
    }
    m_flags = m__io->read_u1();
    m_delay_time = m__io->read_u2le();
    m_transparent_idx = m__io->read_u1();
    m_terminator = m__io->read_bytes(1);
    if (!(terminator() == std::string("\x00", 1))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x00", 1), terminator(), _io(), std::string("/types/ext_graphic_control/seq/4"));
    }
}

gif_t::ext_graphic_control_t::~ext_graphic_control_t() {
    _clean_up();
}

void gif_t::ext_graphic_control_t::_clean_up() {
}

bool gif_t::ext_graphic_control_t::transparent_color_flag() {
    if (f_transparent_color_flag)
        return m_transparent_color_flag;
    m_transparent_color_flag = (flags() & 1) != 0;
    f_transparent_color_flag = true;
    return m_transparent_color_flag;
}

bool gif_t::ext_graphic_control_t::user_input_flag() {
    if (f_user_input_flag)
        return m_user_input_flag;
    m_user_input_flag = (flags() & 2) != 0;
    f_user_input_flag = true;
    return m_user_input_flag;
}

gif_t::subblock_t::subblock_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gif_t::subblock_t::_read() {
    m_len_bytes = m__io->read_u1();
    m_bytes = m__io->read_bytes(len_bytes());
}

gif_t::subblock_t::~subblock_t() {
    _clean_up();
}

void gif_t::subblock_t::_clean_up() {
}

gif_t::application_id_t::application_id_t(kaitai::kstream* p__io, gif_t::ext_application_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gif_t::application_id_t::_read() {
    m_len_bytes = m__io->read_u1();
    if (!(len_bytes() == 11)) {
        throw kaitai::validation_not_equal_error<uint8_t>(11, len_bytes(), _io(), std::string("/types/application_id/seq/0"));
    }
    m_application_identifier = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ASCII"));
    m_application_auth_code = m__io->read_bytes(3);
}

gif_t::application_id_t::~application_id_t() {
    _clean_up();
}

void gif_t::application_id_t::_clean_up() {
}

gif_t::ext_application_t::ext_application_t(kaitai::kstream* p__io, gif_t::extension_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_application_id = nullptr;
    m_subblocks = nullptr;
    _read();
}

void gif_t::ext_application_t::_read() {
    m_application_id = std::unique_ptr<application_id_t>(new application_id_t(m__io, this, m__root));
    m_subblocks = std::unique_ptr<std::vector<std::unique_ptr<subblock_t>>>(new std::vector<std::unique_ptr<subblock_t>>());
    {
        int i = 0;
        subblock_t* _;
        do {
            _ = new subblock_t(m__io, this, m__root);
            m_subblocks->push_back(std::move(std::unique_ptr<subblock_t>(_)));
            i++;
        } while (!(_->len_bytes() == 0));
    }
}

gif_t::ext_application_t::~ext_application_t() {
    _clean_up();
}

void gif_t::ext_application_t::_clean_up() {
}

gif_t::subblocks_t::subblocks_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void gif_t::subblocks_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<subblock_t>>>(new std::vector<std::unique_ptr<subblock_t>>());
    {
        int i = 0;
        subblock_t* _;
        do {
            _ = new subblock_t(m__io, this, m__root);
            m_entries->push_back(std::move(std::unique_ptr<subblock_t>(_)));
            i++;
        } while (!(_->len_bytes() == 0));
    }
}

gif_t::subblocks_t::~subblocks_t() {
    _clean_up();
}

void gif_t::subblocks_t::_clean_up() {
}

gif_t::extension_t::extension_t(kaitai::kstream* p__io, gif_t::block_t* p__parent, gif_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gif_t::extension_t::_read() {
    m_label = static_cast<gif_t::extension_label_t>(m__io->read_u1());
    switch (label()) {
    case gif_t::EXTENSION_LABEL_APPLICATION: {
        m_body = std::unique_ptr<ext_application_t>(new ext_application_t(m__io, this, m__root));
        break;
    }
    case gif_t::EXTENSION_LABEL_COMMENT: {
        m_body = std::unique_ptr<subblocks_t>(new subblocks_t(m__io, this, m__root));
        break;
    }
    case gif_t::EXTENSION_LABEL_GRAPHIC_CONTROL: {
        m_body = std::unique_ptr<ext_graphic_control_t>(new ext_graphic_control_t(m__io, this, m__root));
        break;
    }
    default: {
        m_body = std::unique_ptr<subblocks_t>(new subblocks_t(m__io, this, m__root));
        break;
    }
    }
}

gif_t::extension_t::~extension_t() {
    _clean_up();
}

void gif_t::extension_t::_clean_up() {
}