Android Dynamic Partitions metadata: C++11/STL parsing library

The metadata stored by Android at the beginning of a "super" partition, which is what it calls a disk partition that holds one or more Dynamic Partitions. Dynamic Partitions do more or less the same thing that LVM does on Linux, allowing Android to map ranges of non-contiguous extents to a single logical device. This metadata holds that mapping.

Application

Android

File extension

img

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

This page hosts a formal specification of Android Dynamic Partitions metadata 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.img", 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:
    android_super_t data(&ks);
    

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

data.root() // => get root

C++11/STL source code to parse Android Dynamic Partitions metadata

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

/**
 * The metadata stored by Android at the beginning of a "super" partition, which
 * is what it calls a disk partition that holds one or more Dynamic Partitions.
 * Dynamic Partitions do more or less the same thing that LVM does on Linux,
 * allowing Android to map ranges of non-contiguous extents to a single logical
 * device. This metadata holds that mapping.
 * \sa https://source.android.com/devices/tech/ota/dynamic_partitions Source
 * \sa https://android.googlesource.com/platform/system/core/+/refs/tags/android-11.0.0_r8/fs_mgr/liblp/include/liblp/metadata_format.h Source
 */

class android_super_t : public kaitai::kstruct {

public:
    class root_t;
    class geometry_t;
    class metadata_t;

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

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

public:
    ~android_super_t();

    class root_t : public kaitai::kstruct {

    public:

        root_t(kaitai::kstream* p__io, android_super_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

    public:
        ~root_t();

    private:
        std::unique_ptr<geometry_t> m_primary_geometry;
        std::unique_ptr<geometry_t> m_backup_geometry;
        std::unique_ptr<std::vector<std::unique_ptr<metadata_t>>> m_primary_metadata;
        std::unique_ptr<std::vector<std::unique_ptr<metadata_t>>> m_backup_metadata;
        android_super_t* m__root;
        android_super_t* m__parent;
        std::string m__raw_primary_geometry;
        std::unique_ptr<kaitai::kstream> m__io__raw_primary_geometry;
        std::string m__raw_backup_geometry;
        std::unique_ptr<kaitai::kstream> m__io__raw_backup_geometry;
        std::unique_ptr<std::vector<std::string>> m__raw_primary_metadata;
        std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>> m__io__raw_primary_metadata;
        std::unique_ptr<std::vector<std::string>> m__raw_backup_metadata;
        std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>> m__io__raw_backup_metadata;

    public:
        geometry_t* primary_geometry() const { return m_primary_geometry.get(); }
        geometry_t* backup_geometry() const { return m_backup_geometry.get(); }
        std::vector<std::unique_ptr<metadata_t>>* primary_metadata() const { return m_primary_metadata.get(); }
        std::vector<std::unique_ptr<metadata_t>>* backup_metadata() const { return m_backup_metadata.get(); }
        android_super_t* _root() const { return m__root; }
        android_super_t* _parent() const { return m__parent; }
        std::string _raw_primary_geometry() const { return m__raw_primary_geometry; }
        kaitai::kstream* _io__raw_primary_geometry() const { return m__io__raw_primary_geometry.get(); }
        std::string _raw_backup_geometry() const { return m__raw_backup_geometry; }
        kaitai::kstream* _io__raw_backup_geometry() const { return m__io__raw_backup_geometry.get(); }
        std::vector<std::string>* _raw_primary_metadata() const { return m__raw_primary_metadata.get(); }
        std::vector<std::unique_ptr<kaitai::kstream>>* _io__raw_primary_metadata() const { return m__io__raw_primary_metadata.get(); }
        std::vector<std::string>* _raw_backup_metadata() const { return m__raw_backup_metadata.get(); }
        std::vector<std::unique_ptr<kaitai::kstream>>* _io__raw_backup_metadata() const { return m__io__raw_backup_metadata.get(); }
    };

    class geometry_t : public kaitai::kstruct {

    public:

        geometry_t(kaitai::kstream* p__io, android_super_t::root_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

    public:
        ~geometry_t();

    private:
        std::string m_magic;
        uint32_t m_struct_size;
        std::string m_checksum;
        uint32_t m_metadata_max_size;
        uint32_t m_metadata_slot_count;
        uint32_t m_logical_block_size;
        android_super_t* m__root;
        android_super_t::root_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint32_t struct_size() const { return m_struct_size; }

        /**
         * SHA-256 hash of struct_size bytes from beginning of geometry,
         * calculated as if checksum were zeroed out
         */
        std::string checksum() const { return m_checksum; }
        uint32_t metadata_max_size() const { return m_metadata_max_size; }
        uint32_t metadata_slot_count() const { return m_metadata_slot_count; }
        uint32_t logical_block_size() const { return m_logical_block_size; }
        android_super_t* _root() const { return m__root; }
        android_super_t::root_t* _parent() const { return m__parent; }
    };

    class metadata_t : public kaitai::kstruct {

    public:
        class block_device_t;
        class extent_t;
        class table_descriptor_t;
        class partition_t;
        class group_t;

        enum table_kind_t {
            TABLE_KIND_PARTITIONS = 0,
            TABLE_KIND_EXTENTS = 1,
            TABLE_KIND_GROUPS = 2,
            TABLE_KIND_BLOCK_DEVICES = 3
        };

        metadata_t(kaitai::kstream* p__io, android_super_t::root_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

    public:
        ~metadata_t();

        class block_device_t : public kaitai::kstruct {

        public:

            block_device_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

        public:
            ~block_device_t();

        private:
            uint64_t m_first_logical_sector;
            uint32_t m_alignment;
            uint32_t m_alignment_offset;
            uint64_t m_size;
            std::string m_partition_name;
            bool m_flag_slot_suffixed;
            uint64_t m_flags_reserved;
            android_super_t* m__root;
            android_super_t::metadata_t::table_descriptor_t* m__parent;

        public:
            uint64_t first_logical_sector() const { return m_first_logical_sector; }
            uint32_t alignment() const { return m_alignment; }
            uint32_t alignment_offset() const { return m_alignment_offset; }
            uint64_t size() const { return m_size; }
            std::string partition_name() const { return m_partition_name; }
            bool flag_slot_suffixed() const { return m_flag_slot_suffixed; }
            uint64_t flags_reserved() const { return m_flags_reserved; }
            android_super_t* _root() const { return m__root; }
            android_super_t::metadata_t::table_descriptor_t* _parent() const { return m__parent; }
        };

        class extent_t : public kaitai::kstruct {

        public:

            enum target_type_t {
                TARGET_TYPE_LINEAR = 0,
                TARGET_TYPE_ZERO = 1
            };

            extent_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

        public:
            ~extent_t();

        private:
            uint64_t m_num_sectors;
            target_type_t m_target_type;
            uint64_t m_target_data;
            uint32_t m_target_source;
            android_super_t* m__root;
            android_super_t::metadata_t::table_descriptor_t* m__parent;

        public:
            uint64_t num_sectors() const { return m_num_sectors; }
            target_type_t target_type() const { return m_target_type; }
            uint64_t target_data() const { return m_target_data; }
            uint32_t target_source() const { return m_target_source; }
            android_super_t* _root() const { return m__root; }
            android_super_t::metadata_t::table_descriptor_t* _parent() const { return m__parent; }
        };

        class table_descriptor_t : public kaitai::kstruct {

        public:

            table_descriptor_t(table_kind_t p_kind, kaitai::kstream* p__io, android_super_t::metadata_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

        public:
            ~table_descriptor_t();

        private:
            bool f_table;
            std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstruct>>> m_table;

        public:
            std::vector<std::unique_ptr<kaitai::kstruct>>* table();

        private:
            uint32_t m_offset;
            uint32_t m_num_entries;
            uint32_t m_entry_size;
            table_kind_t m_kind;
            android_super_t* m__root;
            android_super_t::metadata_t* m__parent;
            std::unique_ptr<std::vector<std::string>> m__raw_table;
            std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>> m__io__raw_table;

        public:
            uint32_t offset() const { return m_offset; }
            uint32_t num_entries() const { return m_num_entries; }
            uint32_t entry_size() const { return m_entry_size; }
            table_kind_t kind() const { return m_kind; }
            android_super_t* _root() const { return m__root; }
            android_super_t::metadata_t* _parent() const { return m__parent; }
            std::vector<std::string>* _raw_table() const { return m__raw_table.get(); }
            std::vector<std::unique_ptr<kaitai::kstream>>* _io__raw_table() const { return m__io__raw_table.get(); }
        };

        class partition_t : public kaitai::kstruct {

        public:

            partition_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

        public:
            ~partition_t();

        private:
            std::string m_name;
            bool m_attr_readonly;
            bool m_attr_slot_suffixed;
            bool m_attr_updated;
            bool m_attr_disabled;
            uint64_t m_attrs_reserved;
            uint32_t m_first_extent_index;
            uint32_t m_num_extents;
            uint32_t m_group_index;
            android_super_t* m__root;
            android_super_t::metadata_t::table_descriptor_t* m__parent;

        public:
            std::string name() const { return m_name; }
            bool attr_readonly() const { return m_attr_readonly; }
            bool attr_slot_suffixed() const { return m_attr_slot_suffixed; }
            bool attr_updated() const { return m_attr_updated; }
            bool attr_disabled() const { return m_attr_disabled; }
            uint64_t attrs_reserved() const { return m_attrs_reserved; }
            uint32_t first_extent_index() const { return m_first_extent_index; }
            uint32_t num_extents() const { return m_num_extents; }
            uint32_t group_index() const { return m_group_index; }
            android_super_t* _root() const { return m__root; }
            android_super_t::metadata_t::table_descriptor_t* _parent() const { return m__parent; }
        };

        class group_t : public kaitai::kstruct {

        public:

            group_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent = nullptr, android_super_t* p__root = nullptr);

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

        public:
            ~group_t();

        private:
            std::string m_name;
            bool m_flag_slot_suffixed;
            uint64_t m_flags_reserved;
            uint64_t m_maximum_size;
            android_super_t* m__root;
            android_super_t::metadata_t::table_descriptor_t* m__parent;

        public:
            std::string name() const { return m_name; }
            bool flag_slot_suffixed() const { return m_flag_slot_suffixed; }
            uint64_t flags_reserved() const { return m_flags_reserved; }
            uint64_t maximum_size() const { return m_maximum_size; }
            android_super_t* _root() const { return m__root; }
            android_super_t::metadata_t::table_descriptor_t* _parent() const { return m__parent; }
        };

    private:
        std::string m_magic;
        uint16_t m_major_version;
        uint16_t m_minor_version;
        uint32_t m_header_size;
        std::string m_header_checksum;
        uint32_t m_tables_size;
        std::string m_tables_checksum;
        std::unique_ptr<table_descriptor_t> m_partitions;
        std::unique_ptr<table_descriptor_t> m_extents;
        std::unique_ptr<table_descriptor_t> m_groups;
        std::unique_ptr<table_descriptor_t> m_block_devices;
        android_super_t* m__root;
        android_super_t::root_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint16_t major_version() const { return m_major_version; }
        uint16_t minor_version() const { return m_minor_version; }
        uint32_t header_size() const { return m_header_size; }

        /**
         * SHA-256 hash of header_size bytes from beginning of metadata,
         * calculated as if header_checksum were zeroed out
         */
        std::string header_checksum() const { return m_header_checksum; }
        uint32_t tables_size() const { return m_tables_size; }

        /**
         * SHA-256 hash of tables_size bytes from end of header
         */
        std::string tables_checksum() const { return m_tables_checksum; }
        table_descriptor_t* partitions() const { return m_partitions.get(); }
        table_descriptor_t* extents() const { return m_extents.get(); }
        table_descriptor_t* groups() const { return m_groups.get(); }
        table_descriptor_t* block_devices() const { return m_block_devices.get(); }
        android_super_t* _root() const { return m__root; }
        android_super_t::root_t* _parent() const { return m__parent; }
    };

private:
    bool f_root;
    std::unique_ptr<root_t> m_root;

public:
    root_t* root();

private:
    android_super_t* m__root;
    kaitai::kstruct* m__parent;

public:
    android_super_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

android_super.cpp

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

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

android_super_t::android_super_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_root = nullptr;
    f_root = false;
    _read();
}

void android_super_t::_read() {
}

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

void android_super_t::_clean_up() {
    if (f_root) {
    }
}

android_super_t::root_t::root_t(kaitai::kstream* p__io, android_super_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_primary_geometry = nullptr;
    m__io__raw_primary_geometry = nullptr;
    m_backup_geometry = nullptr;
    m__io__raw_backup_geometry = nullptr;
    m_primary_metadata = nullptr;
    m__raw_primary_metadata = nullptr;
    m__io__raw_primary_metadata = nullptr;
    m_backup_metadata = nullptr;
    m__raw_backup_metadata = nullptr;
    m__io__raw_backup_metadata = nullptr;
    _read();
}

void android_super_t::root_t::_read() {
    m__raw_primary_geometry = m__io->read_bytes(4096);
    m__io__raw_primary_geometry = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_primary_geometry));
    m_primary_geometry = std::unique_ptr<geometry_t>(new geometry_t(m__io__raw_primary_geometry.get(), this, m__root));
    m__raw_backup_geometry = m__io->read_bytes(4096);
    m__io__raw_backup_geometry = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_backup_geometry));
    m_backup_geometry = std::unique_ptr<geometry_t>(new geometry_t(m__io__raw_backup_geometry.get(), this, m__root));
    int l_primary_metadata = primary_geometry()->metadata_slot_count();
    m__raw_primary_metadata = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    m__raw_primary_metadata->reserve(l_primary_metadata);
    m__io__raw_primary_metadata = std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>>(new std::vector<std::unique_ptr<kaitai::kstream>>());
    m__io__raw_primary_metadata->reserve(l_primary_metadata);
    m_primary_metadata = std::unique_ptr<std::vector<std::unique_ptr<metadata_t>>>(new std::vector<std::unique_ptr<metadata_t>>());
    m_primary_metadata->reserve(l_primary_metadata);
    for (int i = 0; i < l_primary_metadata; i++) {
        m__raw_primary_metadata->push_back(std::move(m__io->read_bytes(primary_geometry()->metadata_max_size())));
        kaitai::kstream* io__raw_primary_metadata = new kaitai::kstream(m__raw_primary_metadata->at(m__raw_primary_metadata->size() - 1));
        m__io__raw_primary_metadata->emplace_back(io__raw_primary_metadata);
        m_primary_metadata->push_back(std::move(std::unique_ptr<metadata_t>(new metadata_t(io__raw_primary_metadata, this, m__root))));
    }
    int l_backup_metadata = primary_geometry()->metadata_slot_count();
    m__raw_backup_metadata = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    m__raw_backup_metadata->reserve(l_backup_metadata);
    m__io__raw_backup_metadata = std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>>(new std::vector<std::unique_ptr<kaitai::kstream>>());
    m__io__raw_backup_metadata->reserve(l_backup_metadata);
    m_backup_metadata = std::unique_ptr<std::vector<std::unique_ptr<metadata_t>>>(new std::vector<std::unique_ptr<metadata_t>>());
    m_backup_metadata->reserve(l_backup_metadata);
    for (int i = 0; i < l_backup_metadata; i++) {
        m__raw_backup_metadata->push_back(std::move(m__io->read_bytes(primary_geometry()->metadata_max_size())));
        kaitai::kstream* io__raw_backup_metadata = new kaitai::kstream(m__raw_backup_metadata->at(m__raw_backup_metadata->size() - 1));
        m__io__raw_backup_metadata->emplace_back(io__raw_backup_metadata);
        m_backup_metadata->push_back(std::move(std::unique_ptr<metadata_t>(new metadata_t(io__raw_backup_metadata, this, m__root))));
    }
}

android_super_t::root_t::~root_t() {
    _clean_up();
}

void android_super_t::root_t::_clean_up() {
}

android_super_t::geometry_t::geometry_t(kaitai::kstream* p__io, android_super_t::root_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void android_super_t::geometry_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x67\x44\x6C\x61", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x67\x44\x6C\x61", 4), magic(), _io(), std::string("/types/geometry/seq/0"));
    }
    m_struct_size = m__io->read_u4le();
    m_checksum = m__io->read_bytes(32);
    m_metadata_max_size = m__io->read_u4le();
    m_metadata_slot_count = m__io->read_u4le();
    m_logical_block_size = m__io->read_u4le();
}

android_super_t::geometry_t::~geometry_t() {
    _clean_up();
}

void android_super_t::geometry_t::_clean_up() {
}

android_super_t::metadata_t::metadata_t(kaitai::kstream* p__io, android_super_t::root_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_partitions = nullptr;
    m_extents = nullptr;
    m_groups = nullptr;
    m_block_devices = nullptr;
    _read();
}

void android_super_t::metadata_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x30\x50\x4C\x41", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x30\x50\x4C\x41", 4), magic(), _io(), std::string("/types/metadata/seq/0"));
    }
    m_major_version = m__io->read_u2le();
    m_minor_version = m__io->read_u2le();
    m_header_size = m__io->read_u4le();
    m_header_checksum = m__io->read_bytes(32);
    m_tables_size = m__io->read_u4le();
    m_tables_checksum = m__io->read_bytes(32);
    m_partitions = std::unique_ptr<table_descriptor_t>(new table_descriptor_t(android_super_t::metadata_t::TABLE_KIND_PARTITIONS, m__io, this, m__root));
    m_extents = std::unique_ptr<table_descriptor_t>(new table_descriptor_t(android_super_t::metadata_t::TABLE_KIND_EXTENTS, m__io, this, m__root));
    m_groups = std::unique_ptr<table_descriptor_t>(new table_descriptor_t(android_super_t::metadata_t::TABLE_KIND_GROUPS, m__io, this, m__root));
    m_block_devices = std::unique_ptr<table_descriptor_t>(new table_descriptor_t(android_super_t::metadata_t::TABLE_KIND_BLOCK_DEVICES, m__io, this, m__root));
}

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

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

android_super_t::metadata_t::block_device_t::block_device_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void android_super_t::metadata_t::block_device_t::_read() {
    m_first_logical_sector = m__io->read_u8le();
    m_alignment = m__io->read_u4le();
    m_alignment_offset = m__io->read_u4le();
    m_size = m__io->read_u8le();
    m_partition_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(m__io->read_bytes(36), 0, false), std::string("UTF-8"));
    m_flag_slot_suffixed = m__io->read_bits_int_le(1);
    m_flags_reserved = m__io->read_bits_int_le(31);
}

android_super_t::metadata_t::block_device_t::~block_device_t() {
    _clean_up();
}

void android_super_t::metadata_t::block_device_t::_clean_up() {
}

android_super_t::metadata_t::extent_t::extent_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void android_super_t::metadata_t::extent_t::_read() {
    m_num_sectors = m__io->read_u8le();
    m_target_type = static_cast<android_super_t::metadata_t::extent_t::target_type_t>(m__io->read_u4le());
    m_target_data = m__io->read_u8le();
    m_target_source = m__io->read_u4le();
}

android_super_t::metadata_t::extent_t::~extent_t() {
    _clean_up();
}

void android_super_t::metadata_t::extent_t::_clean_up() {
}

android_super_t::metadata_t::table_descriptor_t::table_descriptor_t(table_kind_t p_kind, kaitai::kstream* p__io, android_super_t::metadata_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_kind = p_kind;
    m_table = nullptr;
    m__raw_table = nullptr;
    m__io__raw_table = nullptr;
    f_table = false;
    _read();
}

void android_super_t::metadata_t::table_descriptor_t::_read() {
    m_offset = m__io->read_u4le();
    m_num_entries = m__io->read_u4le();
    m_entry_size = m__io->read_u4le();
}

android_super_t::metadata_t::table_descriptor_t::~table_descriptor_t() {
    _clean_up();
}

void android_super_t::metadata_t::table_descriptor_t::_clean_up() {
    if (f_table) {
    }
}

std::vector<std::unique_ptr<kaitai::kstruct>>* android_super_t::metadata_t::table_descriptor_t::table() {
    if (f_table)
        return m_table.get();
    std::streampos _pos = m__io->pos();
    m__io->seek((_parent()->header_size() + offset()));
    int l_table = num_entries();
    m__raw_table = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    m__raw_table->reserve(l_table);
    m__io__raw_table = std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>>(new std::vector<std::unique_ptr<kaitai::kstream>>());
    m__io__raw_table->reserve(l_table);
    m_table = std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstruct>>>(new std::vector<std::unique_ptr<kaitai::kstruct>>());
    m_table->reserve(l_table);
    for (int i = 0; i < l_table; i++) {
        switch (kind()) {
        case android_super_t::metadata_t::TABLE_KIND_PARTITIONS: {
            m__raw_table->push_back(std::move(m__io->read_bytes(entry_size())));
            kaitai::kstream* io__raw_table = new kaitai::kstream(m__raw_table->at(m__raw_table->size() - 1));
            m__io__raw_table->emplace_back(io__raw_table);
            m_table->push_back(std::move(std::unique_ptr<partition_t>(new partition_t(io__raw_table, this, m__root))));
            break;
        }
        case android_super_t::metadata_t::TABLE_KIND_EXTENTS: {
            m__raw_table->push_back(std::move(m__io->read_bytes(entry_size())));
            kaitai::kstream* io__raw_table = new kaitai::kstream(m__raw_table->at(m__raw_table->size() - 1));
            m__io__raw_table->emplace_back(io__raw_table);
            m_table->push_back(std::move(std::unique_ptr<extent_t>(new extent_t(io__raw_table, this, m__root))));
            break;
        }
        case android_super_t::metadata_t::TABLE_KIND_GROUPS: {
            m__raw_table->push_back(std::move(m__io->read_bytes(entry_size())));
            kaitai::kstream* io__raw_table = new kaitai::kstream(m__raw_table->at(m__raw_table->size() - 1));
            m__io__raw_table->emplace_back(io__raw_table);
            m_table->push_back(std::move(std::unique_ptr<group_t>(new group_t(io__raw_table, this, m__root))));
            break;
        }
        case android_super_t::metadata_t::TABLE_KIND_BLOCK_DEVICES: {
            m__raw_table->push_back(std::move(m__io->read_bytes(entry_size())));
            kaitai::kstream* io__raw_table = new kaitai::kstream(m__raw_table->at(m__raw_table->size() - 1));
            m__io__raw_table->emplace_back(io__raw_table);
            m_table->push_back(std::move(std::unique_ptr<block_device_t>(new block_device_t(io__raw_table, this, m__root))));
            break;
        }
        default: {
            m__raw_table->push_back(std::move(m__io->read_bytes(entry_size())));
            break;
        }
        }
    }
    m__io->seek(_pos);
    f_table = true;
    return m_table.get();
}

android_super_t::metadata_t::partition_t::partition_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void android_super_t::metadata_t::partition_t::_read() {
    m_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(m__io->read_bytes(36), 0, false), std::string("UTF-8"));
    m_attr_readonly = m__io->read_bits_int_le(1);
    m_attr_slot_suffixed = m__io->read_bits_int_le(1);
    m_attr_updated = m__io->read_bits_int_le(1);
    m_attr_disabled = m__io->read_bits_int_le(1);
    m_attrs_reserved = m__io->read_bits_int_le(28);
    m__io->align_to_byte();
    m_first_extent_index = m__io->read_u4le();
    m_num_extents = m__io->read_u4le();
    m_group_index = m__io->read_u4le();
}

android_super_t::metadata_t::partition_t::~partition_t() {
    _clean_up();
}

void android_super_t::metadata_t::partition_t::_clean_up() {
}

android_super_t::metadata_t::group_t::group_t(kaitai::kstream* p__io, android_super_t::metadata_t::table_descriptor_t* p__parent, android_super_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void android_super_t::metadata_t::group_t::_read() {
    m_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(m__io->read_bytes(36), 0, false), std::string("UTF-8"));
    m_flag_slot_suffixed = m__io->read_bits_int_le(1);
    m_flags_reserved = m__io->read_bits_int_le(31);
    m__io->align_to_byte();
    m_maximum_size = m__io->read_u8le();
}

android_super_t::metadata_t::group_t::~group_t() {
    _clean_up();
}

void android_super_t::metadata_t::group_t::_clean_up() {
}

android_super_t::root_t* android_super_t::root() {
    if (f_root)
        return m_root.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(4096);
    m_root = std::unique_ptr<root_t>(new root_t(m__io, this, m__root));
    m__io->seek(_pos);
    f_root = true;
    return m_root.get();
}