MCAP: C++11/STL parsing library

MCAP is a modular container format and logging library for pub/sub messages with arbitrary message serialization. It is primarily intended for use in robotics applications, and works well under various workloads, resource constraints, and durability requirements.

Time values (log_time, publish_time, create_time) are represented in nanoseconds since a user-understood epoch (i.e. Unix epoch, robot boot time, etc.)

File extension

mcap

KS implementation details

License: Apache-2.0

This page hosts a formal specification of MCAP 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.mcap", 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:
    mcap_t data(&ks);
    

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

data.header_magic() // => get header magic

C++11/STL source code to parse MCAP

mcap.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

/**
 * MCAP is a modular container format and logging library for pub/sub messages with
 * arbitrary message serialization. It is primarily intended for use in robotics
 * applications, and works well under various workloads, resource constraints, and
 * durability requirements.
 * 
 * Time values (`log_time`, `publish_time`, `create_time`) are represented in
 * nanoseconds since a user-understood epoch (i.e. Unix epoch, robot boot time,
 * etc.)
 * \sa https://github.com/foxglove/mcap/tree/c1cc51d/docs/specification#readme Source
 */

class mcap_t : public kaitai::kstruct {

public:
    class prefixed_str_t;
    class chunk_t;
    class data_end_t;
    class channel_t;
    class message_index_t;
    class statistics_t;
    class attachment_index_t;
    class schema_t;
    class map_str_str_t;
    class summary_offset_t;
    class attachment_t;
    class metadata_t;
    class header_t;
    class message_t;
    class tuple_str_str_t;
    class metadata_index_t;
    class magic_t;
    class records_t;
    class footer_t;
    class record_t;
    class chunk_index_t;

    enum opcode_t {
        OPCODE_HEADER = 1,
        OPCODE_FOOTER = 2,
        OPCODE_SCHEMA = 3,
        OPCODE_CHANNEL = 4,
        OPCODE_MESSAGE = 5,
        OPCODE_CHUNK = 6,
        OPCODE_MESSAGE_INDEX = 7,
        OPCODE_CHUNK_INDEX = 8,
        OPCODE_ATTACHMENT = 9,
        OPCODE_ATTACHMENT_INDEX = 10,
        OPCODE_STATISTICS = 11,
        OPCODE_METADATA = 12,
        OPCODE_METADATA_INDEX = 13,
        OPCODE_SUMMARY_OFFSET = 14,
        OPCODE_DATA_END = 15
    };

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

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

public:
    ~mcap_t();

    class prefixed_str_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~prefixed_str_t();

    private:
        uint32_t m_len_str;
        std::string m_str;
        mcap_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        uint32_t len_str() const { return m_len_str; }
        std::string str() const { return m_str; }
        mcap_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class chunk_t : public kaitai::kstruct {

    public:

        chunk_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~chunk_t();

    private:
        uint64_t m_message_start_time;
        uint64_t m_message_end_time;
        uint64_t m_uncompressed_size;
        uint32_t m_uncompressed_crc32;
        std::unique_ptr<prefixed_str_t> m_compression;
        uint64_t m_len_records;
        std::unique_ptr<records_t> m_records;
        bool n_records;

    public:
        bool _is_null_records() { records(); return n_records; };

    private:
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_records;
        std::unique_ptr<kaitai::kstream> m__io__raw_records;

    public:
        uint64_t message_start_time() const { return m_message_start_time; }
        uint64_t message_end_time() const { return m_message_end_time; }
        uint64_t uncompressed_size() const { return m_uncompressed_size; }

        /**
         * CRC-32 checksum of uncompressed `records` field. A value of zero indicates that
         * CRC validation should not be performed.
         */
        uint32_t uncompressed_crc32() const { return m_uncompressed_crc32; }
        prefixed_str_t* compression() const { return m_compression.get(); }
        uint64_t len_records() const { return m_len_records; }
        records_t* records() const { return m_records.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_records() const { return m__raw_records; }
        kaitai::kstream* _io__raw_records() const { return m__io__raw_records.get(); }
    };

    class data_end_t : public kaitai::kstruct {

    public:

        data_end_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~data_end_t();

    private:
        uint32_t m_data_section_crc32;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:

        /**
         * CRC-32 of all bytes in the data section. A value of 0 indicates the CRC-32 is not
         * available.
         */
        uint32_t data_section_crc32() const { return m_data_section_crc32; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class channel_t : public kaitai::kstruct {

    public:

        channel_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~channel_t();

    private:
        uint16_t m_id;
        uint16_t m_schema_id;
        std::unique_ptr<prefixed_str_t> m_topic;
        std::unique_ptr<prefixed_str_t> m_message_encoding;
        std::unique_ptr<map_str_str_t> m_metadata;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:
        uint16_t id() const { return m_id; }
        uint16_t schema_id() const { return m_schema_id; }
        prefixed_str_t* topic() const { return m_topic.get(); }
        prefixed_str_t* message_encoding() const { return m_message_encoding.get(); }
        map_str_str_t* metadata() const { return m_metadata.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class message_index_t : public kaitai::kstruct {

    public:
        class message_index_entry_t;
        class message_index_entries_t;

        message_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~message_index_t();

        class message_index_entry_t : public kaitai::kstruct {

        public:

            message_index_entry_t(kaitai::kstream* p__io, mcap_t::message_index_t::message_index_entries_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~message_index_entry_t();

        private:
            uint64_t m_log_time;
            uint64_t m_offset;
            mcap_t* m__root;
            mcap_t::message_index_t::message_index_entries_t* m__parent;

        public:
            uint64_t log_time() const { return m_log_time; }
            uint64_t offset() const { return m_offset; }
            mcap_t* _root() const { return m__root; }
            mcap_t::message_index_t::message_index_entries_t* _parent() const { return m__parent; }
        };

        class message_index_entries_t : public kaitai::kstruct {

        public:

            message_index_entries_t(kaitai::kstream* p__io, mcap_t::message_index_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~message_index_entries_t();

        private:
            std::unique_ptr<std::vector<std::unique_ptr<message_index_entry_t>>> m_entries;
            mcap_t* m__root;
            mcap_t::message_index_t* m__parent;

        public:
            std::vector<std::unique_ptr<message_index_entry_t>>* entries() const { return m_entries.get(); }
            mcap_t* _root() const { return m__root; }
            mcap_t::message_index_t* _parent() const { return m__parent; }
        };

    private:
        uint16_t m_channel_id;
        uint32_t m_len_records;
        std::unique_ptr<message_index_entries_t> m_records;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_records;
        std::unique_ptr<kaitai::kstream> m__io__raw_records;

    public:
        uint16_t channel_id() const { return m_channel_id; }
        uint32_t len_records() const { return m_len_records; }
        message_index_entries_t* records() const { return m_records.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_records() const { return m__raw_records; }
        kaitai::kstream* _io__raw_records() const { return m__io__raw_records.get(); }
    };

    class statistics_t : public kaitai::kstruct {

    public:
        class channel_message_counts_t;
        class channel_message_count_t;

        statistics_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~statistics_t();

        class channel_message_counts_t : public kaitai::kstruct {

        public:

            channel_message_counts_t(kaitai::kstream* p__io, mcap_t::statistics_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~channel_message_counts_t();

        private:
            std::unique_ptr<std::vector<std::unique_ptr<channel_message_count_t>>> m_entries;
            mcap_t* m__root;
            mcap_t::statistics_t* m__parent;

        public:
            std::vector<std::unique_ptr<channel_message_count_t>>* entries() const { return m_entries.get(); }
            mcap_t* _root() const { return m__root; }
            mcap_t::statistics_t* _parent() const { return m__parent; }
        };

        class channel_message_count_t : public kaitai::kstruct {

        public:

            channel_message_count_t(kaitai::kstream* p__io, mcap_t::statistics_t::channel_message_counts_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~channel_message_count_t();

        private:
            uint16_t m_channel_id;
            uint64_t m_message_count;
            mcap_t* m__root;
            mcap_t::statistics_t::channel_message_counts_t* m__parent;

        public:
            uint16_t channel_id() const { return m_channel_id; }
            uint64_t message_count() const { return m_message_count; }
            mcap_t* _root() const { return m__root; }
            mcap_t::statistics_t::channel_message_counts_t* _parent() const { return m__parent; }
        };

    private:
        uint64_t m_message_count;
        uint16_t m_schema_count;
        uint32_t m_channel_count;
        uint32_t m_attachment_count;
        uint32_t m_metadata_count;
        uint32_t m_chunk_count;
        uint64_t m_message_start_time;
        uint64_t m_message_end_time;
        uint32_t m_len_channel_message_counts;
        std::unique_ptr<channel_message_counts_t> m_channel_message_counts;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_channel_message_counts;
        std::unique_ptr<kaitai::kstream> m__io__raw_channel_message_counts;

    public:
        uint64_t message_count() const { return m_message_count; }
        uint16_t schema_count() const { return m_schema_count; }
        uint32_t channel_count() const { return m_channel_count; }
        uint32_t attachment_count() const { return m_attachment_count; }
        uint32_t metadata_count() const { return m_metadata_count; }
        uint32_t chunk_count() const { return m_chunk_count; }
        uint64_t message_start_time() const { return m_message_start_time; }
        uint64_t message_end_time() const { return m_message_end_time; }
        uint32_t len_channel_message_counts() const { return m_len_channel_message_counts; }
        channel_message_counts_t* channel_message_counts() const { return m_channel_message_counts.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_channel_message_counts() const { return m__raw_channel_message_counts; }
        kaitai::kstream* _io__raw_channel_message_counts() const { return m__io__raw_channel_message_counts.get(); }
    };

    class attachment_index_t : public kaitai::kstruct {

    public:

        attachment_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~attachment_index_t();

    private:
        bool f_attachment;
        std::unique_ptr<record_t> m_attachment;

    public:
        record_t* attachment();

    private:
        uint64_t m_ofs_attachment;
        uint64_t m_len_attachment;
        uint64_t m_log_time;
        uint64_t m_create_time;
        uint64_t m_data_size;
        std::unique_ptr<prefixed_str_t> m_name;
        std::unique_ptr<prefixed_str_t> m_content_type;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_attachment;
        std::unique_ptr<kaitai::kstream> m__io__raw_attachment;

    public:
        uint64_t ofs_attachment() const { return m_ofs_attachment; }
        uint64_t len_attachment() const { return m_len_attachment; }
        uint64_t log_time() const { return m_log_time; }
        uint64_t create_time() const { return m_create_time; }
        uint64_t data_size() const { return m_data_size; }
        prefixed_str_t* name() const { return m_name.get(); }
        prefixed_str_t* content_type() const { return m_content_type.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_attachment() const { return m__raw_attachment; }
        kaitai::kstream* _io__raw_attachment() const { return m__io__raw_attachment.get(); }
    };

    class schema_t : public kaitai::kstruct {

    public:

        schema_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~schema_t();

    private:
        uint16_t m_id;
        std::unique_ptr<prefixed_str_t> m_name;
        std::unique_ptr<prefixed_str_t> m_encoding;
        uint32_t m_len_data;
        std::string m_data;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:
        uint16_t id() const { return m_id; }
        prefixed_str_t* name() const { return m_name.get(); }
        prefixed_str_t* encoding() const { return m_encoding.get(); }
        uint32_t len_data() const { return m_len_data; }
        std::string data() const { return m_data; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class map_str_str_t : public kaitai::kstruct {

    public:
        class entries_t;

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

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

    public:
        ~map_str_str_t();

        class entries_t : public kaitai::kstruct {

        public:

            entries_t(kaitai::kstream* p__io, mcap_t::map_str_str_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~entries_t();

        private:
            std::unique_ptr<std::vector<std::unique_ptr<tuple_str_str_t>>> m_entries;
            mcap_t* m__root;
            mcap_t::map_str_str_t* m__parent;

        public:
            std::vector<std::unique_ptr<tuple_str_str_t>>* entries() const { return m_entries.get(); }
            mcap_t* _root() const { return m__root; }
            mcap_t::map_str_str_t* _parent() const { return m__parent; }
        };

    private:
        uint32_t m_len_entries;
        std::unique_ptr<entries_t> m_entries;
        mcap_t* m__root;
        kaitai::kstruct* m__parent;
        std::string m__raw_entries;
        std::unique_ptr<kaitai::kstream> m__io__raw_entries;

    public:
        uint32_t len_entries() const { return m_len_entries; }
        entries_t* entries() const { return m_entries.get(); }
        mcap_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
        std::string _raw_entries() const { return m__raw_entries; }
        kaitai::kstream* _io__raw_entries() const { return m__io__raw_entries.get(); }
    };

    class summary_offset_t : public kaitai::kstruct {

    public:

        summary_offset_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~summary_offset_t();

    private:
        bool f_group;
        std::unique_ptr<records_t> m_group;

    public:
        records_t* group();

    private:
        opcode_t m_group_opcode;
        uint64_t m_ofs_group;
        uint64_t m_len_group;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_group;
        std::unique_ptr<kaitai::kstream> m__io__raw_group;

    public:
        opcode_t group_opcode() const { return m_group_opcode; }
        uint64_t ofs_group() const { return m_ofs_group; }
        uint64_t len_group() const { return m_len_group; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_group() const { return m__raw_group; }
        kaitai::kstream* _io__raw_group() const { return m__io__raw_group.get(); }
    };

    class attachment_t : public kaitai::kstruct {

    public:

        attachment_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~attachment_t();

    private:
        bool f_crc32_input_end;
        int32_t m_crc32_input_end;

    public:
        int32_t crc32_input_end();

    private:
        bool f_crc32_input;
        std::string m_crc32_input;

    public:
        std::string crc32_input();

    private:
        uint64_t m_log_time;
        uint64_t m_create_time;
        std::unique_ptr<prefixed_str_t> m_name;
        std::unique_ptr<prefixed_str_t> m_content_type;
        uint64_t m_len_data;
        std::string m_data;
        std::string m_invoke_crc32_input_end;
        bool n_invoke_crc32_input_end;

    public:
        bool _is_null_invoke_crc32_input_end() { invoke_crc32_input_end(); return n_invoke_crc32_input_end; };

    private:
        uint32_t m_crc32;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:
        uint64_t log_time() const { return m_log_time; }
        uint64_t create_time() const { return m_create_time; }
        prefixed_str_t* name() const { return m_name.get(); }
        prefixed_str_t* content_type() const { return m_content_type.get(); }
        uint64_t len_data() const { return m_len_data; }
        std::string data() const { return m_data; }
        std::string invoke_crc32_input_end() const { return m_invoke_crc32_input_end; }

        /**
         * CRC-32 checksum of preceding fields in the record. A value of zero indicates that
         * CRC validation should not be performed.
         */
        uint32_t crc32() const { return m_crc32; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class metadata_t : public kaitai::kstruct {

    public:

        metadata_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~metadata_t();

    private:
        std::unique_ptr<prefixed_str_t> m_name;
        std::unique_ptr<map_str_str_t> m_metadata;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:
        prefixed_str_t* name() const { return m_name.get(); }
        map_str_str_t* metadata() const { return m_metadata.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class header_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~header_t();

    private:
        std::unique_ptr<prefixed_str_t> m_profile;
        std::unique_ptr<prefixed_str_t> m_library;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:
        prefixed_str_t* profile() const { return m_profile.get(); }
        prefixed_str_t* library() const { return m_library.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class message_t : public kaitai::kstruct {

    public:

        message_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~message_t();

    private:
        uint16_t m_channel_id;
        uint32_t m_sequence;
        uint64_t m_log_time;
        uint64_t m_publish_time;
        std::string m_data;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;

    public:
        uint16_t channel_id() const { return m_channel_id; }
        uint32_t sequence() const { return m_sequence; }
        uint64_t log_time() const { return m_log_time; }
        uint64_t publish_time() const { return m_publish_time; }
        std::string data() const { return m_data; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
    };

    class tuple_str_str_t : public kaitai::kstruct {

    public:

        tuple_str_str_t(kaitai::kstream* p__io, mcap_t::map_str_str_t::entries_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~tuple_str_str_t();

    private:
        std::unique_ptr<prefixed_str_t> m_key;
        std::unique_ptr<prefixed_str_t> m_value;
        mcap_t* m__root;
        mcap_t::map_str_str_t::entries_t* m__parent;

    public:
        prefixed_str_t* key() const { return m_key.get(); }
        prefixed_str_t* value() const { return m_value.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::map_str_str_t::entries_t* _parent() const { return m__parent; }
    };

    class metadata_index_t : public kaitai::kstruct {

    public:

        metadata_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~metadata_index_t();

    private:
        bool f_metadata;
        std::unique_ptr<record_t> m_metadata;

    public:
        record_t* metadata();

    private:
        uint64_t m_ofs_metadata;
        uint64_t m_len_metadata;
        std::unique_ptr<prefixed_str_t> m_name;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_metadata;
        std::unique_ptr<kaitai::kstream> m__io__raw_metadata;

    public:
        uint64_t ofs_metadata() const { return m_ofs_metadata; }
        uint64_t len_metadata() const { return m_len_metadata; }
        prefixed_str_t* name() const { return m_name.get(); }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_metadata() const { return m__raw_metadata; }
        kaitai::kstream* _io__raw_metadata() const { return m__io__raw_metadata.get(); }
    };

    class magic_t : public kaitai::kstruct {

    public:

        magic_t(kaitai::kstream* p__io, mcap_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~magic_t();

    private:
        std::string m_magic;
        mcap_t* m__root;
        mcap_t* m__parent;

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

    class records_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~records_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<record_t>>> m_records;
        mcap_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        std::vector<std::unique_ptr<record_t>>* records() const { return m_records.get(); }
        mcap_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class footer_t : public kaitai::kstruct {

    public:

        footer_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~footer_t();

    private:
        bool f_summary_section;
        std::unique_ptr<records_t> m_summary_section;
        bool n_summary_section;

    public:
        bool _is_null_summary_section() { summary_section(); return n_summary_section; };

    private:

    public:
        records_t* summary_section();

    private:
        bool f_summary_offset_section;
        std::unique_ptr<records_t> m_summary_offset_section;
        bool n_summary_offset_section;

    public:
        bool _is_null_summary_offset_section() { summary_offset_section(); return n_summary_offset_section; };

    private:

    public:
        records_t* summary_offset_section();

    private:
        bool f_ofs_summary_crc32_input;
        int32_t m_ofs_summary_crc32_input;

    public:
        int32_t ofs_summary_crc32_input();

    private:
        bool f_summary_crc32_input;
        std::string m_summary_crc32_input;

    public:
        std::string summary_crc32_input();

    private:
        uint64_t m_ofs_summary_section;
        uint64_t m_ofs_summary_offset_section;
        uint32_t m_summary_crc32;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_summary_section;
        bool n__raw_summary_section;

    public:
        bool _is_null__raw_summary_section() { _raw_summary_section(); return n__raw_summary_section; };

    private:
        std::unique_ptr<kaitai::kstream> m__io__raw_summary_section;
        std::string m__raw_summary_offset_section;
        bool n__raw_summary_offset_section;

    public:
        bool _is_null__raw_summary_offset_section() { _raw_summary_offset_section(); return n__raw_summary_offset_section; };

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

    public:
        uint64_t ofs_summary_section() const { return m_ofs_summary_section; }
        uint64_t ofs_summary_offset_section() const { return m_ofs_summary_offset_section; }

        /**
         * A CRC-32 of all bytes from the start of the Summary section up through and
         * including the end of the previous field (summary_offset_start) in the footer
         * record. A value of 0 indicates the CRC-32 is not available.
         */
        uint32_t summary_crc32() const { return m_summary_crc32; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_summary_section() const { return m__raw_summary_section; }
        kaitai::kstream* _io__raw_summary_section() const { return m__io__raw_summary_section.get(); }
        std::string _raw_summary_offset_section() const { return m__raw_summary_offset_section; }
        kaitai::kstream* _io__raw_summary_offset_section() const { return m__io__raw_summary_offset_section.get(); }
    };

    class record_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~record_t();

    private:
        opcode_t m_op;
        uint64_t m_len_body;
        std::unique_ptr<kaitai::kstruct> m_body;
        bool n_body;

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

    private:
        mcap_t* m__root;
        kaitai::kstruct* m__parent;
        std::string m__raw_body;
        std::unique_ptr<kaitai::kstream> m__io__raw_body;

    public:
        opcode_t op() const { return m_op; }
        uint64_t len_body() const { return m_len_body; }
        kaitai::kstruct* body() const { return m_body.get(); }
        mcap_t* _root() const { return m__root; }
        kaitai::kstruct* _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.get(); }
    };

    class chunk_index_t : public kaitai::kstruct {

    public:
        class message_index_offset_t;
        class message_index_offsets_t;

        chunk_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

    public:
        ~chunk_index_t();

        class message_index_offset_t : public kaitai::kstruct {

        public:

            message_index_offset_t(kaitai::kstream* p__io, mcap_t::chunk_index_t::message_index_offsets_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~message_index_offset_t();

        private:
            uint16_t m_channel_id;
            uint64_t m_offset;
            mcap_t* m__root;
            mcap_t::chunk_index_t::message_index_offsets_t* m__parent;

        public:
            uint16_t channel_id() const { return m_channel_id; }
            uint64_t offset() const { return m_offset; }
            mcap_t* _root() const { return m__root; }
            mcap_t::chunk_index_t::message_index_offsets_t* _parent() const { return m__parent; }
        };

        class message_index_offsets_t : public kaitai::kstruct {

        public:

            message_index_offsets_t(kaitai::kstream* p__io, mcap_t::chunk_index_t* p__parent = nullptr, mcap_t* p__root = nullptr);

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

        public:
            ~message_index_offsets_t();

        private:
            std::unique_ptr<std::vector<std::unique_ptr<message_index_offset_t>>> m_entries;
            mcap_t* m__root;
            mcap_t::chunk_index_t* m__parent;

        public:
            std::vector<std::unique_ptr<message_index_offset_t>>* entries() const { return m_entries.get(); }
            mcap_t* _root() const { return m__root; }
            mcap_t::chunk_index_t* _parent() const { return m__parent; }
        };

    private:
        bool f_chunk;
        std::unique_ptr<record_t> m_chunk;

    public:
        record_t* chunk();

    private:
        uint64_t m_message_start_time;
        uint64_t m_message_end_time;
        uint64_t m_ofs_chunk;
        uint64_t m_len_chunk;
        uint32_t m_len_message_index_offsets;
        std::unique_ptr<message_index_offsets_t> m_message_index_offsets;
        uint64_t m_message_index_length;
        std::unique_ptr<prefixed_str_t> m_compression;
        uint64_t m_compressed_size;
        uint64_t m_uncompressed_size;
        mcap_t* m__root;
        mcap_t::record_t* m__parent;
        std::string m__raw_message_index_offsets;
        std::unique_ptr<kaitai::kstream> m__io__raw_message_index_offsets;
        std::string m__raw_chunk;
        std::unique_ptr<kaitai::kstream> m__io__raw_chunk;

    public:
        uint64_t message_start_time() const { return m_message_start_time; }
        uint64_t message_end_time() const { return m_message_end_time; }
        uint64_t ofs_chunk() const { return m_ofs_chunk; }
        uint64_t len_chunk() const { return m_len_chunk; }
        uint32_t len_message_index_offsets() const { return m_len_message_index_offsets; }
        message_index_offsets_t* message_index_offsets() const { return m_message_index_offsets.get(); }
        uint64_t message_index_length() const { return m_message_index_length; }
        prefixed_str_t* compression() const { return m_compression.get(); }
        uint64_t compressed_size() const { return m_compressed_size; }
        uint64_t uncompressed_size() const { return m_uncompressed_size; }
        mcap_t* _root() const { return m__root; }
        mcap_t::record_t* _parent() const { return m__parent; }
        std::string _raw_message_index_offsets() const { return m__raw_message_index_offsets; }
        kaitai::kstream* _io__raw_message_index_offsets() const { return m__io__raw_message_index_offsets.get(); }
        std::string _raw_chunk() const { return m__raw_chunk; }
        kaitai::kstream* _io__raw_chunk() const { return m__io__raw_chunk.get(); }
    };

private:
    bool f_footer;
    std::unique_ptr<record_t> m_footer;

public:
    record_t* footer();

private:
    bool f_ofs_footer;
    int32_t m_ofs_footer;

public:
    int32_t ofs_footer();

private:
    std::unique_ptr<magic_t> m_header_magic;
    std::unique_ptr<std::vector<std::unique_ptr<record_t>>> m_records;
    std::unique_ptr<magic_t> m_footer_magic;
    mcap_t* m__root;
    kaitai::kstruct* m__parent;
    std::string m__raw_footer;
    std::unique_ptr<kaitai::kstream> m__io__raw_footer;

public:
    magic_t* header_magic() const { return m_header_magic.get(); }
    std::vector<std::unique_ptr<record_t>>* records() const { return m_records.get(); }
    magic_t* footer_magic() const { return m_footer_magic.get(); }
    mcap_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::string _raw_footer() const { return m__raw_footer; }
    kaitai::kstream* _io__raw_footer() const { return m__io__raw_footer.get(); }
};

mcap.cpp

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

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

mcap_t::mcap_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_header_magic = nullptr;
    m_records = nullptr;
    m_footer_magic = nullptr;
    m_footer = nullptr;
    m__io__raw_footer = nullptr;
    f_footer = false;
    f_ofs_footer = false;
    _read();
}

void mcap_t::_read() {
    m_header_magic = std::unique_ptr<magic_t>(new magic_t(m__io, this, m__root));
    m_records = std::unique_ptr<std::vector<std::unique_ptr<record_t>>>(new std::vector<std::unique_ptr<record_t>>());
    {
        int i = 0;
        record_t* _;
        do {
            _ = new record_t(m__io, this, m__root);
            m_records->push_back(std::move(std::unique_ptr<record_t>(_)));
            i++;
        } while (!(_->op() == mcap_t::OPCODE_FOOTER));
    }
    m_footer_magic = std::unique_ptr<magic_t>(new magic_t(m__io, this, m__root));
}

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

void mcap_t::_clean_up() {
    if (f_footer) {
    }
}

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

void mcap_t::prefixed_str_t::_read() {
    m_len_str = m__io->read_u4le();
    m_str = kaitai::kstream::bytes_to_str(m__io->read_bytes(len_str()), std::string("UTF-8"));
}

mcap_t::prefixed_str_t::~prefixed_str_t() {
    _clean_up();
}

void mcap_t::prefixed_str_t::_clean_up() {
}

mcap_t::chunk_t::chunk_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_compression = nullptr;
    m__io__raw_records = nullptr;
    _read();
}

void mcap_t::chunk_t::_read() {
    m_message_start_time = m__io->read_u8le();
    m_message_end_time = m__io->read_u8le();
    m_uncompressed_size = m__io->read_u8le();
    m_uncompressed_crc32 = m__io->read_u4le();
    m_compression = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_len_records = m__io->read_u8le();
    n_records = true;
    {
        std::string on = compression()->str();
        if (on == std::string("")) {
            n_records = false;
            m__raw_records = m__io->read_bytes(len_records());
            m__io__raw_records = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_records));
            m_records = std::unique_ptr<records_t>(new records_t(m__io__raw_records.get(), this, m__root));
        }
        else {
            m__raw_records = m__io->read_bytes(len_records());
        }
    }
}

mcap_t::chunk_t::~chunk_t() {
    _clean_up();
}

void mcap_t::chunk_t::_clean_up() {
    if (!n_records) {
    }
}

mcap_t::data_end_t::data_end_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mcap_t::data_end_t::_read() {
    m_data_section_crc32 = m__io->read_u4le();
}

mcap_t::data_end_t::~data_end_t() {
    _clean_up();
}

void mcap_t::data_end_t::_clean_up() {
}

mcap_t::channel_t::channel_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_topic = nullptr;
    m_message_encoding = nullptr;
    m_metadata = nullptr;
    _read();
}

void mcap_t::channel_t::_read() {
    m_id = m__io->read_u2le();
    m_schema_id = m__io->read_u2le();
    m_topic = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_message_encoding = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_metadata = std::unique_ptr<map_str_str_t>(new map_str_str_t(m__io, this, m__root));
}

mcap_t::channel_t::~channel_t() {
    _clean_up();
}

void mcap_t::channel_t::_clean_up() {
}

mcap_t::message_index_t::message_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_records = nullptr;
    m__io__raw_records = nullptr;
    _read();
}

void mcap_t::message_index_t::_read() {
    m_channel_id = m__io->read_u2le();
    m_len_records = m__io->read_u4le();
    m__raw_records = m__io->read_bytes(len_records());
    m__io__raw_records = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_records));
    m_records = std::unique_ptr<message_index_entries_t>(new message_index_entries_t(m__io__raw_records.get(), this, m__root));
}

mcap_t::message_index_t::~message_index_t() {
    _clean_up();
}

void mcap_t::message_index_t::_clean_up() {
}

mcap_t::message_index_t::message_index_entry_t::message_index_entry_t(kaitai::kstream* p__io, mcap_t::message_index_t::message_index_entries_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mcap_t::message_index_t::message_index_entry_t::_read() {
    m_log_time = m__io->read_u8le();
    m_offset = m__io->read_u8le();
}

mcap_t::message_index_t::message_index_entry_t::~message_index_entry_t() {
    _clean_up();
}

void mcap_t::message_index_t::message_index_entry_t::_clean_up() {
}

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

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

mcap_t::message_index_t::message_index_entries_t::~message_index_entries_t() {
    _clean_up();
}

void mcap_t::message_index_t::message_index_entries_t::_clean_up() {
}

mcap_t::statistics_t::statistics_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_channel_message_counts = nullptr;
    m__io__raw_channel_message_counts = nullptr;
    _read();
}

void mcap_t::statistics_t::_read() {
    m_message_count = m__io->read_u8le();
    m_schema_count = m__io->read_u2le();
    m_channel_count = m__io->read_u4le();
    m_attachment_count = m__io->read_u4le();
    m_metadata_count = m__io->read_u4le();
    m_chunk_count = m__io->read_u4le();
    m_message_start_time = m__io->read_u8le();
    m_message_end_time = m__io->read_u8le();
    m_len_channel_message_counts = m__io->read_u4le();
    m__raw_channel_message_counts = m__io->read_bytes(len_channel_message_counts());
    m__io__raw_channel_message_counts = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_channel_message_counts));
    m_channel_message_counts = std::unique_ptr<channel_message_counts_t>(new channel_message_counts_t(m__io__raw_channel_message_counts.get(), this, m__root));
}

mcap_t::statistics_t::~statistics_t() {
    _clean_up();
}

void mcap_t::statistics_t::_clean_up() {
}

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

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

mcap_t::statistics_t::channel_message_counts_t::~channel_message_counts_t() {
    _clean_up();
}

void mcap_t::statistics_t::channel_message_counts_t::_clean_up() {
}

mcap_t::statistics_t::channel_message_count_t::channel_message_count_t(kaitai::kstream* p__io, mcap_t::statistics_t::channel_message_counts_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mcap_t::statistics_t::channel_message_count_t::_read() {
    m_channel_id = m__io->read_u2le();
    m_message_count = m__io->read_u8le();
}

mcap_t::statistics_t::channel_message_count_t::~channel_message_count_t() {
    _clean_up();
}

void mcap_t::statistics_t::channel_message_count_t::_clean_up() {
}

mcap_t::attachment_index_t::attachment_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_name = nullptr;
    m_content_type = nullptr;
    m_attachment = nullptr;
    m__io__raw_attachment = nullptr;
    f_attachment = false;
    _read();
}

void mcap_t::attachment_index_t::_read() {
    m_ofs_attachment = m__io->read_u8le();
    m_len_attachment = m__io->read_u8le();
    m_log_time = m__io->read_u8le();
    m_create_time = m__io->read_u8le();
    m_data_size = m__io->read_u8le();
    m_name = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_content_type = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
}

mcap_t::attachment_index_t::~attachment_index_t() {
    _clean_up();
}

void mcap_t::attachment_index_t::_clean_up() {
    if (f_attachment) {
    }
}

mcap_t::record_t* mcap_t::attachment_index_t::attachment() {
    if (f_attachment)
        return m_attachment.get();
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_attachment());
    m__raw_attachment = io->read_bytes(len_attachment());
    m__io__raw_attachment = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_attachment));
    m_attachment = std::unique_ptr<record_t>(new record_t(m__io__raw_attachment.get(), this, m__root));
    io->seek(_pos);
    f_attachment = true;
    return m_attachment.get();
}

mcap_t::schema_t::schema_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_name = nullptr;
    m_encoding = nullptr;
    _read();
}

void mcap_t::schema_t::_read() {
    m_id = m__io->read_u2le();
    m_name = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_encoding = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_len_data = m__io->read_u4le();
    m_data = m__io->read_bytes(len_data());
}

mcap_t::schema_t::~schema_t() {
    _clean_up();
}

void mcap_t::schema_t::_clean_up() {
}

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

void mcap_t::map_str_str_t::_read() {
    m_len_entries = m__io->read_u4le();
    m__raw_entries = m__io->read_bytes(len_entries());
    m__io__raw_entries = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_entries));
    m_entries = std::unique_ptr<entries_t>(new entries_t(m__io__raw_entries.get(), this, m__root));
}

mcap_t::map_str_str_t::~map_str_str_t() {
    _clean_up();
}

void mcap_t::map_str_str_t::_clean_up() {
}

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

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

mcap_t::map_str_str_t::entries_t::~entries_t() {
    _clean_up();
}

void mcap_t::map_str_str_t::entries_t::_clean_up() {
}

mcap_t::summary_offset_t::summary_offset_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_group = nullptr;
    m__io__raw_group = nullptr;
    f_group = false;
    _read();
}

void mcap_t::summary_offset_t::_read() {
    m_group_opcode = static_cast<mcap_t::opcode_t>(m__io->read_u1());
    m_ofs_group = m__io->read_u8le();
    m_len_group = m__io->read_u8le();
}

mcap_t::summary_offset_t::~summary_offset_t() {
    _clean_up();
}

void mcap_t::summary_offset_t::_clean_up() {
    if (f_group) {
    }
}

mcap_t::records_t* mcap_t::summary_offset_t::group() {
    if (f_group)
        return m_group.get();
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_group());
    m__raw_group = io->read_bytes(len_group());
    m__io__raw_group = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_group));
    m_group = std::unique_ptr<records_t>(new records_t(m__io__raw_group.get(), this, m__root));
    io->seek(_pos);
    f_group = true;
    return m_group.get();
}

mcap_t::attachment_t::attachment_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_name = nullptr;
    m_content_type = nullptr;
    f_crc32_input_end = false;
    f_crc32_input = false;
    _read();
}

void mcap_t::attachment_t::_read() {
    m_log_time = m__io->read_u8le();
    m_create_time = m__io->read_u8le();
    m_name = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_content_type = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_len_data = m__io->read_u8le();
    m_data = m__io->read_bytes(len_data());
    n_invoke_crc32_input_end = true;
    if (crc32_input_end() >= 0) {
        n_invoke_crc32_input_end = false;
        m_invoke_crc32_input_end = m__io->read_bytes(0);
    }
    m_crc32 = m__io->read_u4le();
}

mcap_t::attachment_t::~attachment_t() {
    _clean_up();
}

void mcap_t::attachment_t::_clean_up() {
    if (!n_invoke_crc32_input_end) {
    }
    if (f_crc32_input) {
    }
}

int32_t mcap_t::attachment_t::crc32_input_end() {
    if (f_crc32_input_end)
        return m_crc32_input_end;
    m_crc32_input_end = _io()->pos();
    f_crc32_input_end = true;
    return m_crc32_input_end;
}

std::string mcap_t::attachment_t::crc32_input() {
    if (f_crc32_input)
        return m_crc32_input;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    m_crc32_input = m__io->read_bytes(crc32_input_end());
    m__io->seek(_pos);
    f_crc32_input = true;
    return m_crc32_input;
}

mcap_t::metadata_t::metadata_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_name = nullptr;
    m_metadata = nullptr;
    _read();
}

void mcap_t::metadata_t::_read() {
    m_name = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_metadata = std::unique_ptr<map_str_str_t>(new map_str_str_t(m__io, this, m__root));
}

mcap_t::metadata_t::~metadata_t() {
    _clean_up();
}

void mcap_t::metadata_t::_clean_up() {
}

mcap_t::header_t::header_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_profile = nullptr;
    m_library = nullptr;
    _read();
}

void mcap_t::header_t::_read() {
    m_profile = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_library = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
}

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

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

mcap_t::message_t::message_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mcap_t::message_t::_read() {
    m_channel_id = m__io->read_u2le();
    m_sequence = m__io->read_u4le();
    m_log_time = m__io->read_u8le();
    m_publish_time = m__io->read_u8le();
    m_data = m__io->read_bytes_full();
}

mcap_t::message_t::~message_t() {
    _clean_up();
}

void mcap_t::message_t::_clean_up() {
}

mcap_t::tuple_str_str_t::tuple_str_str_t(kaitai::kstream* p__io, mcap_t::map_str_str_t::entries_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_key = nullptr;
    m_value = nullptr;
    _read();
}

void mcap_t::tuple_str_str_t::_read() {
    m_key = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_value = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
}

mcap_t::tuple_str_str_t::~tuple_str_str_t() {
    _clean_up();
}

void mcap_t::tuple_str_str_t::_clean_up() {
}

mcap_t::metadata_index_t::metadata_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_name = nullptr;
    m_metadata = nullptr;
    m__io__raw_metadata = nullptr;
    f_metadata = false;
    _read();
}

void mcap_t::metadata_index_t::_read() {
    m_ofs_metadata = m__io->read_u8le();
    m_len_metadata = m__io->read_u8le();
    m_name = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
}

mcap_t::metadata_index_t::~metadata_index_t() {
    _clean_up();
}

void mcap_t::metadata_index_t::_clean_up() {
    if (f_metadata) {
    }
}

mcap_t::record_t* mcap_t::metadata_index_t::metadata() {
    if (f_metadata)
        return m_metadata.get();
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_metadata());
    m__raw_metadata = io->read_bytes(len_metadata());
    m__io__raw_metadata = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_metadata));
    m_metadata = std::unique_ptr<record_t>(new record_t(m__io__raw_metadata.get(), this, m__root));
    io->seek(_pos);
    f_metadata = true;
    return m_metadata.get();
}

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

void mcap_t::magic_t::_read() {
    m_magic = m__io->read_bytes(8);
    if (!(magic() == std::string("\x89\x4D\x43\x41\x50\x30\x0D\x0A", 8))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x89\x4D\x43\x41\x50\x30\x0D\x0A", 8), magic(), _io(), std::string("/types/magic/seq/0"));
    }
}

mcap_t::magic_t::~magic_t() {
    _clean_up();
}

void mcap_t::magic_t::_clean_up() {
}

mcap_t::records_t::records_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_records = nullptr;
    _read();
}

void mcap_t::records_t::_read() {
    m_records = std::unique_ptr<std::vector<std::unique_ptr<record_t>>>(new std::vector<std::unique_ptr<record_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_records->push_back(std::move(std::unique_ptr<record_t>(new record_t(m__io, this, m__root))));
            i++;
        }
    }
}

mcap_t::records_t::~records_t() {
    _clean_up();
}

void mcap_t::records_t::_clean_up() {
}

mcap_t::footer_t::footer_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_summary_section = nullptr;
    m__io__raw_summary_section = nullptr;
    m_summary_offset_section = nullptr;
    m__io__raw_summary_offset_section = nullptr;
    f_summary_section = false;
    f_summary_offset_section = false;
    f_ofs_summary_crc32_input = false;
    f_summary_crc32_input = false;
    _read();
}

void mcap_t::footer_t::_read() {
    m_ofs_summary_section = m__io->read_u8le();
    m_ofs_summary_offset_section = m__io->read_u8le();
    m_summary_crc32 = m__io->read_u4le();
}

mcap_t::footer_t::~footer_t() {
    _clean_up();
}

void mcap_t::footer_t::_clean_up() {
    if (f_summary_section && !n_summary_section) {
    }
    if (f_summary_offset_section && !n_summary_offset_section) {
    }
    if (f_summary_crc32_input) {
    }
}

mcap_t::records_t* mcap_t::footer_t::summary_section() {
    if (f_summary_section)
        return m_summary_section.get();
    n_summary_section = true;
    if (ofs_summary_section() != 0) {
        n_summary_section = false;
        kaitai::kstream *io = _root()->_io();
        std::streampos _pos = io->pos();
        io->seek(ofs_summary_section());
        m__raw_summary_section = io->read_bytes((((ofs_summary_offset_section() != 0) ? (ofs_summary_offset_section()) : (_root()->ofs_footer())) - ofs_summary_section()));
        m__io__raw_summary_section = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_summary_section));
        m_summary_section = std::unique_ptr<records_t>(new records_t(m__io__raw_summary_section.get(), this, m__root));
        io->seek(_pos);
        f_summary_section = true;
    }
    return m_summary_section.get();
}

mcap_t::records_t* mcap_t::footer_t::summary_offset_section() {
    if (f_summary_offset_section)
        return m_summary_offset_section.get();
    n_summary_offset_section = true;
    if (ofs_summary_offset_section() != 0) {
        n_summary_offset_section = false;
        kaitai::kstream *io = _root()->_io();
        std::streampos _pos = io->pos();
        io->seek(ofs_summary_offset_section());
        m__raw_summary_offset_section = io->read_bytes((_root()->ofs_footer() - ofs_summary_offset_section()));
        m__io__raw_summary_offset_section = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_summary_offset_section));
        m_summary_offset_section = std::unique_ptr<records_t>(new records_t(m__io__raw_summary_offset_section.get(), this, m__root));
        io->seek(_pos);
        f_summary_offset_section = true;
    }
    return m_summary_offset_section.get();
}

int32_t mcap_t::footer_t::ofs_summary_crc32_input() {
    if (f_ofs_summary_crc32_input)
        return m_ofs_summary_crc32_input;
    m_ofs_summary_crc32_input = ((ofs_summary_section() != 0) ? (ofs_summary_section()) : (_root()->ofs_footer()));
    f_ofs_summary_crc32_input = true;
    return m_ofs_summary_crc32_input;
}

std::string mcap_t::footer_t::summary_crc32_input() {
    if (f_summary_crc32_input)
        return m_summary_crc32_input;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_summary_crc32_input());
    m_summary_crc32_input = io->read_bytes((((_root()->_io()->size() - ofs_summary_crc32_input()) - 8) - 4));
    io->seek(_pos);
    f_summary_crc32_input = true;
    return m_summary_crc32_input;
}

mcap_t::record_t::record_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_body = nullptr;
    _read();
}

void mcap_t::record_t::_read() {
    m_op = static_cast<mcap_t::opcode_t>(m__io->read_u1());
    m_len_body = m__io->read_u8le();
    n_body = true;
    switch (op()) {
    case mcap_t::OPCODE_MESSAGE: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<message_t>(new message_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_METADATA_INDEX: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<metadata_index_t>(new metadata_index_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_CHUNK: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<chunk_t>(new chunk_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_SCHEMA: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<schema_t>(new schema_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_CHUNK_INDEX: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<chunk_index_t>(new chunk_index_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_DATA_END: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<data_end_t>(new data_end_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_ATTACHMENT_INDEX: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<attachment_index_t>(new attachment_index_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_STATISTICS: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<statistics_t>(new statistics_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_MESSAGE_INDEX: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<message_index_t>(new message_index_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_CHANNEL: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<channel_t>(new channel_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_METADATA: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<metadata_t>(new metadata_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_ATTACHMENT: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<attachment_t>(new attachment_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_HEADER: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<header_t>(new header_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_FOOTER: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<footer_t>(new footer_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case mcap_t::OPCODE_SUMMARY_OFFSET: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<summary_offset_t>(new summary_offset_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    default: {
        m__raw_body = m__io->read_bytes(len_body());
        break;
    }
    }
}

mcap_t::record_t::~record_t() {
    _clean_up();
}

void mcap_t::record_t::_clean_up() {
    if (!n_body) {
    }
}

mcap_t::chunk_index_t::chunk_index_t(kaitai::kstream* p__io, mcap_t::record_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_message_index_offsets = nullptr;
    m__io__raw_message_index_offsets = nullptr;
    m_compression = nullptr;
    m_chunk = nullptr;
    m__io__raw_chunk = nullptr;
    f_chunk = false;
    _read();
}

void mcap_t::chunk_index_t::_read() {
    m_message_start_time = m__io->read_u8le();
    m_message_end_time = m__io->read_u8le();
    m_ofs_chunk = m__io->read_u8le();
    m_len_chunk = m__io->read_u8le();
    m_len_message_index_offsets = m__io->read_u4le();
    m__raw_message_index_offsets = m__io->read_bytes(len_message_index_offsets());
    m__io__raw_message_index_offsets = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_message_index_offsets));
    m_message_index_offsets = std::unique_ptr<message_index_offsets_t>(new message_index_offsets_t(m__io__raw_message_index_offsets.get(), this, m__root));
    m_message_index_length = m__io->read_u8le();
    m_compression = std::unique_ptr<prefixed_str_t>(new prefixed_str_t(m__io, this, m__root));
    m_compressed_size = m__io->read_u8le();
    m_uncompressed_size = m__io->read_u8le();
}

mcap_t::chunk_index_t::~chunk_index_t() {
    _clean_up();
}

void mcap_t::chunk_index_t::_clean_up() {
    if (f_chunk) {
    }
}

mcap_t::chunk_index_t::message_index_offset_t::message_index_offset_t(kaitai::kstream* p__io, mcap_t::chunk_index_t::message_index_offsets_t* p__parent, mcap_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mcap_t::chunk_index_t::message_index_offset_t::_read() {
    m_channel_id = m__io->read_u2le();
    m_offset = m__io->read_u8le();
}

mcap_t::chunk_index_t::message_index_offset_t::~message_index_offset_t() {
    _clean_up();
}

void mcap_t::chunk_index_t::message_index_offset_t::_clean_up() {
}

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

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

mcap_t::chunk_index_t::message_index_offsets_t::~message_index_offsets_t() {
    _clean_up();
}

void mcap_t::chunk_index_t::message_index_offsets_t::_clean_up() {
}

mcap_t::record_t* mcap_t::chunk_index_t::chunk() {
    if (f_chunk)
        return m_chunk.get();
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_chunk());
    m__raw_chunk = io->read_bytes(len_chunk());
    m__io__raw_chunk = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_chunk));
    m_chunk = std::unique_ptr<record_t>(new record_t(m__io__raw_chunk.get(), this, m__root));
    io->seek(_pos);
    f_chunk = true;
    return m_chunk.get();
}

mcap_t::record_t* mcap_t::footer() {
    if (f_footer)
        return m_footer.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_footer());
    m__raw_footer = m__io->read_bytes_full();
    m__io__raw_footer = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_footer));
    m_footer = std::unique_ptr<record_t>(new record_t(m__io__raw_footer.get(), this, m__root));
    m__io->seek(_pos);
    f_footer = true;
    return m_footer.get();
}

int32_t mcap_t::ofs_footer() {
    if (f_ofs_footer)
        return m_ofs_footer;
    m_ofs_footer = ((((_io()->size() - 1) - 8) - 20) - 8);
    f_ofs_footer = true;
    return m_ofs_footer;
}