VirtualBox Disk Image: C++11/STL parsing library

A native VirtualBox file format Images for testing can be downloaded from

  • https://www.osboxes.org/virtualbox-images/
  • https://virtualboxes.org/images/
  • https://virtualboximages.com/ or you can convert images of other formats.

Application

["VirtualBox", "QEMU", "VMWare Workstation"]

File extension

vdi

KS implementation details

License: GPL-3.0-or-later

References

This page hosts a formal specification of VirtualBox Disk Image 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.vdi", 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:
    vdi_t data(&ks);
    

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

data.blocks_map() // => block_index = offset_in_virtual_disk / block_size actual_data_offset = blocks_map[block_index]*block_size+metadata_size+offset_in_block
The blocks_map will take up blocks_in_image_max * sizeof(uint32_t) bytes; since the blocks_map is read and written in a single operation, its size needs to be limited to INT_MAX; furthermore, when opening an image, the blocks_map size is rounded up to be aligned on BDRV_SECTOR_SIZE. Therefore this should satisfy the following: blocks_in_image_max * sizeof(uint32_t) + BDRV_SECTOR_SIZE == INT_MAX + 1 (INT_MAX + 1 is the first value not representable as an int) This guarantees that any value below or equal to the constant will, when multiplied by sizeof(uint32_t) and rounded up to a BDRV_SECTOR_SIZE boundary, still be below or equal to INT_MAX.

C++11/STL source code to parse VirtualBox Disk Image

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

/**
 * A native VirtualBox file format
 * Images for testing can be downloaded from
 *  * https://www.osboxes.org/virtualbox-images/
 *  * https://virtualboxes.org/images/
 *  * https://virtualboximages.com/
 * or you can convert images of other formats.
 * \sa https://github.com/qemu/qemu/blob/master/block/vdi.c Source
 */

class vdi_t : public kaitai::kstruct {

public:
    class header_t;
    class blocks_map_t;
    class disk_t;

    enum image_type_t {
        IMAGE_TYPE_DYNAMIC = 1,
        IMAGE_TYPE_STATIC = 2,
        IMAGE_TYPE_UNDO = 3,
        IMAGE_TYPE_DIFF = 4
    };

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

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

public:
    ~vdi_t();

    class header_t : public kaitai::kstruct {

    public:
        class uuid_t;
        class version_t;
        class header_main_t;

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

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

    public:
        ~header_t();

        class uuid_t : public kaitai::kstruct {

        public:

            uuid_t(kaitai::kstream* p__io, vdi_t::header_t::header_main_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

        public:
            ~uuid_t();

        private:
            std::string m_uuid;
            vdi_t* m__root;
            vdi_t::header_t::header_main_t* m__parent;

        public:
            std::string uuid() const { return m_uuid; }
            vdi_t* _root() const { return m__root; }
            vdi_t::header_t::header_main_t* _parent() const { return m__parent; }
        };

        class version_t : public kaitai::kstruct {

        public:

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

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

        public:
            ~version_t();

        private:
            uint16_t m_major;
            uint16_t m_minor;
            vdi_t* m__root;
            vdi_t::header_t* m__parent;

        public:
            uint16_t major() const { return m_major; }
            uint16_t minor() const { return m_minor; }
            vdi_t* _root() const { return m__root; }
            vdi_t::header_t* _parent() const { return m__parent; }
        };

        class header_main_t : public kaitai::kstruct {

        public:
            class geometry_t;
            class flags_t;

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

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

        public:
            ~header_main_t();

            class geometry_t : public kaitai::kstruct {

            public:

                geometry_t(kaitai::kstream* p__io, vdi_t::header_t::header_main_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

            public:
                ~geometry_t();

            private:
                uint32_t m_cylinders;
                uint32_t m_heads;
                uint32_t m_sectors;
                uint32_t m_sector_size;
                vdi_t* m__root;
                vdi_t::header_t::header_main_t* m__parent;

            public:
                uint32_t cylinders() const { return m_cylinders; }
                uint32_t heads() const { return m_heads; }
                uint32_t sectors() const { return m_sectors; }
                uint32_t sector_size() const { return m_sector_size; }
                vdi_t* _root() const { return m__root; }
                vdi_t::header_t::header_main_t* _parent() const { return m__parent; }
            };

            class flags_t : public kaitai::kstruct {

            public:

                flags_t(kaitai::kstream* p__io, vdi_t::header_t::header_main_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

            public:
                ~flags_t();

            private:
                uint64_t m_reserved0;
                bool m_zero_expand;
                uint64_t m_reserved1;
                bool m_diff;
                bool m_fixed;
                uint64_t m_reserved2;
                vdi_t* m__root;
                vdi_t::header_t::header_main_t* m__parent;

            public:
                uint64_t reserved0() const { return m_reserved0; }
                bool zero_expand() const { return m_zero_expand; }
                uint64_t reserved1() const { return m_reserved1; }
                bool diff() const { return m_diff; }
                bool fixed() const { return m_fixed; }
                uint64_t reserved2() const { return m_reserved2; }
                vdi_t* _root() const { return m__root; }
                vdi_t::header_t::header_main_t* _parent() const { return m__parent; }
            };

        private:
            image_type_t m_image_type;
            std::unique_ptr<flags_t> m_image_flags;
            std::string m_description;
            uint32_t m_blocks_map_offset;
            bool n_blocks_map_offset;

        public:
            bool _is_null_blocks_map_offset() { blocks_map_offset(); return n_blocks_map_offset; };

        private:
            uint32_t m_offset_data;
            bool n_offset_data;

        public:
            bool _is_null_offset_data() { offset_data(); return n_offset_data; };

        private:
            std::unique_ptr<geometry_t> m_geometry;
            uint32_t m_reserved1;
            bool n_reserved1;

        public:
            bool _is_null_reserved1() { reserved1(); return n_reserved1; };

        private:
            uint64_t m_disk_size;
            uint32_t m_block_data_size;
            uint32_t m_block_metadata_size;
            bool n_block_metadata_size;

        public:
            bool _is_null_block_metadata_size() { block_metadata_size(); return n_block_metadata_size; };

        private:
            uint32_t m_blocks_in_image;
            uint32_t m_blocks_allocated;
            std::unique_ptr<uuid_t> m_uuid_image;
            std::unique_ptr<uuid_t> m_uuid_last_snap;
            std::unique_ptr<uuid_t> m_uuid_link;
            std::unique_ptr<uuid_t> m_uuid_parent;
            bool n_uuid_parent;

        public:
            bool _is_null_uuid_parent() { uuid_parent(); return n_uuid_parent; };

        private:
            std::unique_ptr<geometry_t> m_lchc_geometry;
            bool n_lchc_geometry;

        public:
            bool _is_null_lchc_geometry() { lchc_geometry(); return n_lchc_geometry; };

        private:
            vdi_t* m__root;
            vdi_t::header_t* m__parent;

        public:
            image_type_t image_type() const { return m_image_type; }
            flags_t* image_flags() const { return m_image_flags.get(); }
            std::string description() const { return m_description; }
            uint32_t blocks_map_offset() const { return m_blocks_map_offset; }
            uint32_t offset_data() const { return m_offset_data; }
            geometry_t* geometry() const { return m_geometry.get(); }
            uint32_t reserved1() const { return m_reserved1; }
            uint64_t disk_size() const { return m_disk_size; }

            /**
             * Size of block (bytes).
             */
            uint32_t block_data_size() const { return m_block_data_size; }
            uint32_t block_metadata_size() const { return m_block_metadata_size; }
            uint32_t blocks_in_image() const { return m_blocks_in_image; }
            uint32_t blocks_allocated() const { return m_blocks_allocated; }
            uuid_t* uuid_image() const { return m_uuid_image.get(); }
            uuid_t* uuid_last_snap() const { return m_uuid_last_snap.get(); }
            uuid_t* uuid_link() const { return m_uuid_link.get(); }
            uuid_t* uuid_parent() const { return m_uuid_parent.get(); }
            geometry_t* lchc_geometry() const { return m_lchc_geometry.get(); }
            vdi_t* _root() const { return m__root; }
            vdi_t::header_t* _parent() const { return m__parent; }
        };

    private:
        bool f_header_size;
        int32_t m_header_size;

    public:
        int32_t header_size();

    private:
        bool f_blocks_map_offset;
        uint32_t m_blocks_map_offset;

    public:
        uint32_t blocks_map_offset();

    private:
        bool f_subheader_size_is_dynamic;
        bool m_subheader_size_is_dynamic;

    public:
        bool subheader_size_is_dynamic();

    private:
        bool f_blocks_offset;
        uint32_t m_blocks_offset;

    public:
        uint32_t blocks_offset();

    private:
        bool f_block_size;
        int32_t m_block_size;

    public:
        int32_t block_size();

    private:
        bool f_blocks_map_size;
        int32_t m_blocks_map_size;

    public:
        int32_t blocks_map_size();

    private:
        std::string m_text;
        std::string m_signature;
        std::unique_ptr<version_t> m_version;
        uint32_t m_header_size_optional;
        bool n_header_size_optional;

    public:
        bool _is_null_header_size_optional() { header_size_optional(); return n_header_size_optional; };

    private:
        std::unique_ptr<header_main_t> m_header_main;
        vdi_t* m__root;
        vdi_t* m__parent;
        std::string m__raw_header_main;
        std::unique_ptr<kaitai::kstream> m__io__raw_header_main;

    public:
        std::string text() const { return m_text; }
        std::string signature() const { return m_signature; }
        version_t* version() const { return m_version.get(); }
        uint32_t header_size_optional() const { return m_header_size_optional; }
        header_main_t* header_main() const { return m_header_main.get(); }
        vdi_t* _root() const { return m__root; }
        vdi_t* _parent() const { return m__parent; }
        std::string _raw_header_main() const { return m__raw_header_main; }
        kaitai::kstream* _io__raw_header_main() const { return m__io__raw_header_main.get(); }
    };

    class blocks_map_t : public kaitai::kstruct {

    public:
        class block_index_t;

        blocks_map_t(kaitai::kstream* p__io, vdi_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

    public:
        ~blocks_map_t();

        class block_index_t : public kaitai::kstruct {

        public:

            block_index_t(kaitai::kstream* p__io, vdi_t::blocks_map_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

        public:
            ~block_index_t();

        private:
            bool f_is_allocated;
            bool m_is_allocated;

        public:
            bool is_allocated();

        private:
            bool f_block;
            block_t* m_block;
            bool n_block;

        public:
            bool _is_null_block() { block(); return n_block; };

        private:

        public:
            block_t* block();

        private:
            uint32_t m_index;
            vdi_t* m__root;
            vdi_t::blocks_map_t* m__parent;

        public:
            uint32_t index() const { return m_index; }
            vdi_t* _root() const { return m__root; }
            vdi_t::blocks_map_t* _parent() const { return m__parent; }
        };

    private:
        std::unique_ptr<std::vector<std::unique_ptr<block_index_t>>> m_index;
        vdi_t* m__root;
        vdi_t* m__parent;

    public:
        std::vector<std::unique_ptr<block_index_t>>* index() const { return m_index.get(); }
        vdi_t* _root() const { return m__root; }
        vdi_t* _parent() const { return m__parent; }
    };

    class disk_t : public kaitai::kstruct {

    public:
        class block_t;

        disk_t(kaitai::kstream* p__io, vdi_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

    public:
        ~disk_t();

        class block_t : public kaitai::kstruct {

        public:
            class sector_t;

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

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

        public:
            ~block_t();

            class sector_t : public kaitai::kstruct {

            public:

                sector_t(kaitai::kstream* p__io, vdi_t::disk_t::block_t* p__parent = nullptr, vdi_t* p__root = nullptr);

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

            public:
                ~sector_t();

            private:
                std::string m_data;
                vdi_t* m__root;
                vdi_t::disk_t::block_t* m__parent;

            public:
                std::string data() const { return m_data; }
                vdi_t* _root() const { return m__root; }
                vdi_t::disk_t::block_t* _parent() const { return m__parent; }
            };

        private:
            std::string m_metadata;
            std::unique_ptr<std::vector<std::unique_ptr<sector_t>>> m_data;
            vdi_t* m__root;
            vdi_t::disk_t* m__parent;
            std::unique_ptr<std::vector<std::string>> m__raw_data;
            std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>> m__io__raw_data;

        public:
            std::string metadata() const { return m_metadata; }
            std::vector<std::unique_ptr<sector_t>>* data() const { return m_data.get(); }
            vdi_t* _root() const { return m__root; }
            vdi_t::disk_t* _parent() const { return m__parent; }
            std::vector<std::string>* _raw_data() const { return m__raw_data.get(); }
            std::vector<std::unique_ptr<kaitai::kstream>>* _io__raw_data() const { return m__io__raw_data.get(); }
        };

    private:
        std::unique_ptr<std::vector<std::unique_ptr<block_t>>> m_blocks;
        vdi_t* m__root;
        vdi_t* m__parent;

    public:
        std::vector<std::unique_ptr<block_t>>* blocks() const { return m_blocks.get(); }
        vdi_t* _root() const { return m__root; }
        vdi_t* _parent() const { return m__parent; }
    };

private:
    bool f_block_discarded;
    int32_t m_block_discarded;

public:
    int32_t block_discarded();

private:
    bool f_block_unallocated;
    int32_t m_block_unallocated;

public:
    int32_t block_unallocated();

private:
    bool f_blocks_map;
    std::unique_ptr<blocks_map_t> m_blocks_map;

public:

    /**
     * block_index = offset_in_virtual_disk / block_size actual_data_offset = blocks_map[block_index]*block_size+metadata_size+offset_in_block
     * The blocks_map will take up blocks_in_image_max * sizeof(uint32_t) bytes; since the blocks_map is read and written in a single operation, its size needs to be limited to INT_MAX; furthermore, when opening an image, the blocks_map size is rounded up to be aligned on BDRV_SECTOR_SIZE. Therefore this should satisfy the following: blocks_in_image_max * sizeof(uint32_t) + BDRV_SECTOR_SIZE == INT_MAX + 1 (INT_MAX + 1 is the first value not representable as an int) This guarantees that any value below or equal to the constant will, when multiplied by sizeof(uint32_t) and rounded up to a BDRV_SECTOR_SIZE boundary, still be below or equal to INT_MAX.
     */
    blocks_map_t* blocks_map();

private:
    bool f_disk;
    std::unique_ptr<disk_t> m_disk;

public:
    disk_t* disk();

private:
    std::unique_ptr<header_t> m_header;
    vdi_t* m__root;
    kaitai::kstruct* m__parent;
    std::string m__raw_blocks_map;
    std::unique_ptr<kaitai::kstream> m__io__raw_blocks_map;

public:
    header_t* header() const { return m_header.get(); }
    vdi_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::string _raw_blocks_map() const { return m__raw_blocks_map; }
    kaitai::kstream* _io__raw_blocks_map() const { return m__io__raw_blocks_map.get(); }
};

vdi.cpp

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

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

vdi_t::vdi_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_header = nullptr;
    m_blocks_map = nullptr;
    m__io__raw_blocks_map = nullptr;
    m_disk = nullptr;
    f_block_discarded = false;
    f_block_unallocated = false;
    f_blocks_map = false;
    f_disk = false;
    _read();
}

void vdi_t::_read() {
    m_header = std::unique_ptr<header_t>(new header_t(m__io, this, m__root));
}

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

void vdi_t::_clean_up() {
    if (f_blocks_map) {
    }
    if (f_disk) {
    }
}

vdi_t::header_t::header_t(kaitai::kstream* p__io, vdi_t* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_version = nullptr;
    m_header_main = nullptr;
    m__io__raw_header_main = nullptr;
    f_header_size = false;
    f_blocks_map_offset = false;
    f_subheader_size_is_dynamic = false;
    f_blocks_offset = false;
    f_block_size = false;
    f_blocks_map_size = false;
    _read();
}

void vdi_t::header_t::_read() {
    m_text = kaitai::kstream::bytes_to_str(m__io->read_bytes(64), std::string("utf-8"));
    m_signature = m__io->read_bytes(4);
    if (!(signature() == std::string("\x7F\x10\xDA\xBE", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x7F\x10\xDA\xBE", 4), signature(), _io(), std::string("/types/header/seq/1"));
    }
    m_version = std::unique_ptr<version_t>(new version_t(m__io, this, m__root));
    n_header_size_optional = true;
    if (subheader_size_is_dynamic()) {
        n_header_size_optional = false;
        m_header_size_optional = m__io->read_u4le();
    }
    m__raw_header_main = m__io->read_bytes(header_size());
    m__io__raw_header_main = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_header_main));
    m_header_main = std::unique_ptr<header_main_t>(new header_main_t(m__io__raw_header_main.get(), this, m__root));
}

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

void vdi_t::header_t::_clean_up() {
    if (!n_header_size_optional) {
    }
}

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

void vdi_t::header_t::uuid_t::_read() {
    m_uuid = m__io->read_bytes(16);
}

vdi_t::header_t::uuid_t::~uuid_t() {
    _clean_up();
}

void vdi_t::header_t::uuid_t::_clean_up() {
}

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

void vdi_t::header_t::version_t::_read() {
    m_major = m__io->read_u2le();
    m_minor = m__io->read_u2le();
}

vdi_t::header_t::version_t::~version_t() {
    _clean_up();
}

void vdi_t::header_t::version_t::_clean_up() {
}

vdi_t::header_t::header_main_t::header_main_t(kaitai::kstream* p__io, vdi_t::header_t* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_image_flags = nullptr;
    m_geometry = nullptr;
    m_uuid_image = nullptr;
    m_uuid_last_snap = nullptr;
    m_uuid_link = nullptr;
    m_uuid_parent = nullptr;
    m_lchc_geometry = nullptr;
    _read();
}

void vdi_t::header_t::header_main_t::_read() {
    m_image_type = static_cast<vdi_t::image_type_t>(m__io->read_u4le());
    m_image_flags = std::unique_ptr<flags_t>(new flags_t(m__io, this, m__root));
    m_description = kaitai::kstream::bytes_to_str(m__io->read_bytes(256), std::string("utf-8"));
    n_blocks_map_offset = true;
    if (_parent()->version()->major() >= 1) {
        n_blocks_map_offset = false;
        m_blocks_map_offset = m__io->read_u4le();
    }
    n_offset_data = true;
    if (_parent()->version()->major() >= 1) {
        n_offset_data = false;
        m_offset_data = m__io->read_u4le();
    }
    m_geometry = std::unique_ptr<geometry_t>(new geometry_t(m__io, this, m__root));
    n_reserved1 = true;
    if (_parent()->version()->major() >= 1) {
        n_reserved1 = false;
        m_reserved1 = m__io->read_u4le();
    }
    m_disk_size = m__io->read_u8le();
    m_block_data_size = m__io->read_u4le();
    n_block_metadata_size = true;
    if (_parent()->version()->major() >= 1) {
        n_block_metadata_size = false;
        m_block_metadata_size = m__io->read_u4le();
    }
    m_blocks_in_image = m__io->read_u4le();
    m_blocks_allocated = m__io->read_u4le();
    m_uuid_image = std::unique_ptr<uuid_t>(new uuid_t(m__io, this, m__root));
    m_uuid_last_snap = std::unique_ptr<uuid_t>(new uuid_t(m__io, this, m__root));
    m_uuid_link = std::unique_ptr<uuid_t>(new uuid_t(m__io, this, m__root));
    n_uuid_parent = true;
    if (_parent()->version()->major() >= 1) {
        n_uuid_parent = false;
        m_uuid_parent = std::unique_ptr<uuid_t>(new uuid_t(m__io, this, m__root));
    }
    n_lchc_geometry = true;
    if ( ((_parent()->version()->major() >= 1) && ((_io()->pos() + 16) <= _io()->size())) ) {
        n_lchc_geometry = false;
        m_lchc_geometry = std::unique_ptr<geometry_t>(new geometry_t(m__io, this, m__root));
    }
}

vdi_t::header_t::header_main_t::~header_main_t() {
    _clean_up();
}

void vdi_t::header_t::header_main_t::_clean_up() {
    if (!n_blocks_map_offset) {
    }
    if (!n_offset_data) {
    }
    if (!n_reserved1) {
    }
    if (!n_block_metadata_size) {
    }
    if (!n_uuid_parent) {
    }
    if (!n_lchc_geometry) {
    }
}

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

void vdi_t::header_t::header_main_t::geometry_t::_read() {
    m_cylinders = m__io->read_u4le();
    m_heads = m__io->read_u4le();
    m_sectors = m__io->read_u4le();
    m_sector_size = m__io->read_u4le();
}

vdi_t::header_t::header_main_t::geometry_t::~geometry_t() {
    _clean_up();
}

void vdi_t::header_t::header_main_t::geometry_t::_clean_up() {
}

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

void vdi_t::header_t::header_main_t::flags_t::_read() {
    m_reserved0 = m__io->read_bits_int_be(15);
    m_zero_expand = m__io->read_bits_int_be(1);
    m_reserved1 = m__io->read_bits_int_be(6);
    m_diff = m__io->read_bits_int_be(1);
    m_fixed = m__io->read_bits_int_be(1);
    m_reserved2 = m__io->read_bits_int_be(8);
}

vdi_t::header_t::header_main_t::flags_t::~flags_t() {
    _clean_up();
}

void vdi_t::header_t::header_main_t::flags_t::_clean_up() {
}

int32_t vdi_t::header_t::header_size() {
    if (f_header_size)
        return m_header_size;
    m_header_size = ((subheader_size_is_dynamic()) ? (header_size_optional()) : (336));
    f_header_size = true;
    return m_header_size;
}

uint32_t vdi_t::header_t::blocks_map_offset() {
    if (f_blocks_map_offset)
        return m_blocks_map_offset;
    m_blocks_map_offset = header_main()->blocks_map_offset();
    f_blocks_map_offset = true;
    return m_blocks_map_offset;
}

bool vdi_t::header_t::subheader_size_is_dynamic() {
    if (f_subheader_size_is_dynamic)
        return m_subheader_size_is_dynamic;
    m_subheader_size_is_dynamic = version()->major() >= 1;
    f_subheader_size_is_dynamic = true;
    return m_subheader_size_is_dynamic;
}

uint32_t vdi_t::header_t::blocks_offset() {
    if (f_blocks_offset)
        return m_blocks_offset;
    m_blocks_offset = header_main()->offset_data();
    f_blocks_offset = true;
    return m_blocks_offset;
}

int32_t vdi_t::header_t::block_size() {
    if (f_block_size)
        return m_block_size;
    m_block_size = (header_main()->block_metadata_size() + header_main()->block_data_size());
    f_block_size = true;
    return m_block_size;
}

int32_t vdi_t::header_t::blocks_map_size() {
    if (f_blocks_map_size)
        return m_blocks_map_size;
    m_blocks_map_size = (((((header_main()->blocks_in_image() * 4) + header_main()->geometry()->sector_size()) - 1) / header_main()->geometry()->sector_size()) * header_main()->geometry()->sector_size());
    f_blocks_map_size = true;
    return m_blocks_map_size;
}

vdi_t::blocks_map_t::blocks_map_t(kaitai::kstream* p__io, vdi_t* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_index = nullptr;
    _read();
}

void vdi_t::blocks_map_t::_read() {
    int l_index = _root()->header()->header_main()->blocks_in_image();
    m_index = std::unique_ptr<std::vector<std::unique_ptr<block_index_t>>>(new std::vector<std::unique_ptr<block_index_t>>());
    m_index->reserve(l_index);
    for (int i = 0; i < l_index; i++) {
        m_index->push_back(std::move(std::unique_ptr<block_index_t>(new block_index_t(m__io, this, m__root))));
    }
}

vdi_t::blocks_map_t::~blocks_map_t() {
    _clean_up();
}

void vdi_t::blocks_map_t::_clean_up() {
}

vdi_t::blocks_map_t::block_index_t::block_index_t(kaitai::kstream* p__io, vdi_t::blocks_map_t* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_is_allocated = false;
    f_block = false;
    _read();
}

void vdi_t::blocks_map_t::block_index_t::_read() {
    m_index = m__io->read_u4le();
}

vdi_t::blocks_map_t::block_index_t::~block_index_t() {
    _clean_up();
}

void vdi_t::blocks_map_t::block_index_t::_clean_up() {
}

bool vdi_t::blocks_map_t::block_index_t::is_allocated() {
    if (f_is_allocated)
        return m_is_allocated;
    m_is_allocated = index() < _root()->block_discarded();
    f_is_allocated = true;
    return m_is_allocated;
}

vdi_t::disk_t::block_t* vdi_t::blocks_map_t::block_index_t::block() {
    if (f_block)
        return m_block;
    n_block = true;
    if (is_allocated()) {
        n_block = false;
        m_block = _root()->disk()->blocks()->at(index());
    }
    f_block = true;
    return m_block;
}

vdi_t::disk_t::disk_t(kaitai::kstream* p__io, vdi_t* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_blocks = nullptr;
    _read();
}

void vdi_t::disk_t::_read() {
    int l_blocks = _root()->header()->header_main()->blocks_in_image();
    m_blocks = std::unique_ptr<std::vector<std::unique_ptr<block_t>>>(new std::vector<std::unique_ptr<block_t>>());
    m_blocks->reserve(l_blocks);
    for (int i = 0; i < l_blocks; i++) {
        m_blocks->push_back(std::move(std::unique_ptr<block_t>(new block_t(m__io, this, m__root))));
    }
}

vdi_t::disk_t::~disk_t() {
    _clean_up();
}

void vdi_t::disk_t::_clean_up() {
}

vdi_t::disk_t::block_t::block_t(kaitai::kstream* p__io, vdi_t::disk_t* p__parent, vdi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_data = nullptr;
    m__raw_data = nullptr;
    m__io__raw_data = nullptr;
    _read();
}

void vdi_t::disk_t::block_t::_read() {
    m_metadata = m__io->read_bytes(_root()->header()->header_main()->block_metadata_size());
    m__raw_data = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    m__io__raw_data = std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>>(new std::vector<std::unique_ptr<kaitai::kstream>>());
    m_data = std::unique_ptr<std::vector<std::unique_ptr<sector_t>>>(new std::vector<std::unique_ptr<sector_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m__raw_data->push_back(std::move(m__io->read_bytes(_root()->header()->header_main()->block_data_size())));
            kaitai::kstream* io__raw_data = new kaitai::kstream(m__raw_data->at(m__raw_data->size() - 1));
            m__io__raw_data->emplace_back(io__raw_data);
            m_data->push_back(std::move(std::unique_ptr<sector_t>(new sector_t(io__raw_data, this, m__root))));
            i++;
        }
    }
}

vdi_t::disk_t::block_t::~block_t() {
    _clean_up();
}

void vdi_t::disk_t::block_t::_clean_up() {
}

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

void vdi_t::disk_t::block_t::sector_t::_read() {
    m_data = m__io->read_bytes(_root()->header()->header_main()->geometry()->sector_size());
}

vdi_t::disk_t::block_t::sector_t::~sector_t() {
    _clean_up();
}

void vdi_t::disk_t::block_t::sector_t::_clean_up() {
}

int32_t vdi_t::block_discarded() {
    if (f_block_discarded)
        return m_block_discarded;
    m_block_discarded = 4294967294UL;
    f_block_discarded = true;
    return m_block_discarded;
}

int32_t vdi_t::block_unallocated() {
    if (f_block_unallocated)
        return m_block_unallocated;
    m_block_unallocated = 4294967295UL;
    f_block_unallocated = true;
    return m_block_unallocated;
}

vdi_t::blocks_map_t* vdi_t::blocks_map() {
    if (f_blocks_map)
        return m_blocks_map.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(header()->blocks_map_offset());
    m__raw_blocks_map = m__io->read_bytes(header()->blocks_map_size());
    m__io__raw_blocks_map = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_blocks_map));
    m_blocks_map = std::unique_ptr<blocks_map_t>(new blocks_map_t(m__io__raw_blocks_map.get(), this, m__root));
    m__io->seek(_pos);
    f_blocks_map = true;
    return m_blocks_map.get();
}

vdi_t::disk_t* vdi_t::disk() {
    if (f_disk)
        return m_disk.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(header()->blocks_offset());
    m_disk = std::unique_ptr<disk_t>(new disk_t(m__io, this, m__root));
    m__io->seek(_pos);
    f_disk = true;
    return m_disk.get();
}