GPT (GUID) partition table: C++/STL parsing library

KS implementation details

License: CC0-1.0

This page hosts a formal specification of GPT (GUID) partition table using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

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.gpt_partition_table", 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:
    gpt_partition_table_t data(&ks);

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

data.sector_size() // => get sector size

C++/STL source code to parse GPT (GUID) partition table

gpt_partition_table.h

#ifndef GPT_PARTITION_TABLE_H_
#define GPT_PARTITION_TABLE_H_

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

#include "kaitai/kaitaistruct.h"

#include <stdint.h>
#include <vector>

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

/**
 * \sa Specification taken from https://en.wikipedia.org/wiki/GUID_Partition_Table
 */

class gpt_partition_table_t : public kaitai::kstruct {

public:
    class partition_entry_t;
    class partition_header_t;

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

private:
    void _read();

public:
    ~gpt_partition_table_t();

    class partition_entry_t : public kaitai::kstruct {

    public:

        partition_entry_t(kaitai::kstream* p__io, gpt_partition_table_t::partition_header_t* p__parent = 0, gpt_partition_table_t* p__root = 0);

    private:
        void _read();

    public:
        ~partition_entry_t();

    private:
        std::string m_type_guid;
        std::string m_guid;
        uint64_t m_first_lba;
        uint64_t m_last_lba;
        uint64_t m_attributes;
        std::string m_name;
        gpt_partition_table_t* m__root;
        gpt_partition_table_t::partition_header_t* m__parent;

    public:
        std::string type_guid() const { return m_type_guid; }
        std::string guid() const { return m_guid; }
        uint64_t first_lba() const { return m_first_lba; }
        uint64_t last_lba() const { return m_last_lba; }
        uint64_t attributes() const { return m_attributes; }
        std::string name() const { return m_name; }
        gpt_partition_table_t* _root() const { return m__root; }
        gpt_partition_table_t::partition_header_t* _parent() const { return m__parent; }
    };

    class partition_header_t : public kaitai::kstruct {

    public:

        partition_header_t(kaitai::kstream* p__io, gpt_partition_table_t* p__parent = 0, gpt_partition_table_t* p__root = 0);

    private:
        void _read();

    public:
        ~partition_header_t();

    private:
        bool f_entries;
        std::vector<partition_entry_t*>* m_entries;

    public:
        std::vector<partition_entry_t*>* entries();

    private:
        std::string m_signature;
        uint32_t m_revision;
        uint32_t m_header_size;
        uint32_t m_crc32_header;
        uint32_t m_reserved;
        uint64_t m_current_lba;
        uint64_t m_backup_lba;
        uint64_t m_first_usable_lba;
        uint64_t m_last_usable_lba;
        std::string m_disk_guid;
        uint64_t m_entries_start;
        uint32_t m_entries_count;
        uint32_t m_entries_size;
        uint32_t m_crc32_array;
        gpt_partition_table_t* m__root;
        gpt_partition_table_t* m__parent;
        std::vector<std::string>* m__raw_entries;
        std::vector<kaitai::kstream*>* m__io__raw_entries;

    public:
        std::string signature() const { return m_signature; }
        uint32_t revision() const { return m_revision; }
        uint32_t header_size() const { return m_header_size; }
        uint32_t crc32_header() const { return m_crc32_header; }
        uint32_t reserved() const { return m_reserved; }
        uint64_t current_lba() const { return m_current_lba; }
        uint64_t backup_lba() const { return m_backup_lba; }
        uint64_t first_usable_lba() const { return m_first_usable_lba; }
        uint64_t last_usable_lba() const { return m_last_usable_lba; }
        std::string disk_guid() const { return m_disk_guid; }
        uint64_t entries_start() const { return m_entries_start; }
        uint32_t entries_count() const { return m_entries_count; }
        uint32_t entries_size() const { return m_entries_size; }
        uint32_t crc32_array() const { return m_crc32_array; }
        gpt_partition_table_t* _root() const { return m__root; }
        gpt_partition_table_t* _parent() const { return m__parent; }
        std::vector<std::string>* _raw_entries() const { return m__raw_entries; }
        std::vector<kaitai::kstream*>* _io__raw_entries() const { return m__io__raw_entries; }
    };

private:
    bool f_sector_size;
    int32_t m_sector_size;

public:
    int32_t sector_size();

private:
    bool f_primary;
    partition_header_t* m_primary;

public:
    partition_header_t* primary();

private:
    bool f_backup;
    partition_header_t* m_backup;

public:
    partition_header_t* backup();

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

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

#endif  // GPT_PARTITION_TABLE_H_

gpt_partition_table.cpp

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

#include "gpt_partition_table.h"



gpt_partition_table_t::gpt_partition_table_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gpt_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    f_sector_size = false;
    f_primary = false;
    f_backup = false;
    _read();
}

void gpt_partition_table_t::_read() {
}

gpt_partition_table_t::~gpt_partition_table_t() {
    if (f_primary) {
        delete m_primary;
    }
    if (f_backup) {
        delete m_backup;
    }
}

gpt_partition_table_t::partition_entry_t::partition_entry_t(kaitai::kstream* p__io, gpt_partition_table_t::partition_header_t* p__parent, gpt_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void gpt_partition_table_t::partition_entry_t::_read() {
    m_type_guid = m__io->read_bytes(16);
    m_guid = m__io->read_bytes(16);
    m_first_lba = m__io->read_u8le();
    m_last_lba = m__io->read_u8le();
    m_attributes = m__io->read_u8le();
    m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(72), std::string("UTF-16LE"));
}

gpt_partition_table_t::partition_entry_t::~partition_entry_t() {
}

gpt_partition_table_t::partition_header_t::partition_header_t(kaitai::kstream* p__io, gpt_partition_table_t* p__parent, gpt_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_entries = false;
    _read();
}

void gpt_partition_table_t::partition_header_t::_read() {
    m_signature = m__io->ensure_fixed_contents(std::string("\x45\x46\x49\x20\x50\x41\x52\x54", 8));
    m_revision = m__io->read_u4le();
    m_header_size = m__io->read_u4le();
    m_crc32_header = m__io->read_u4le();
    m_reserved = m__io->read_u4le();
    m_current_lba = m__io->read_u8le();
    m_backup_lba = m__io->read_u8le();
    m_first_usable_lba = m__io->read_u8le();
    m_last_usable_lba = m__io->read_u8le();
    m_disk_guid = m__io->read_bytes(16);
    m_entries_start = m__io->read_u8le();
    m_entries_count = m__io->read_u4le();
    m_entries_size = m__io->read_u4le();
    m_crc32_array = m__io->read_u4le();
}

gpt_partition_table_t::partition_header_t::~partition_header_t() {
    if (f_entries) {
        delete m__raw_entries;
        for (std::vector<kaitai::kstream*>::iterator it = m__io__raw_entries->begin(); it != m__io__raw_entries->end(); ++it) {
            delete *it;
        }
        delete m__io__raw_entries;
        for (std::vector<partition_entry_t*>::iterator it = m_entries->begin(); it != m_entries->end(); ++it) {
            delete *it;
        }
        delete m_entries;
    }
}

std::vector<gpt_partition_table_t::partition_entry_t*>* gpt_partition_table_t::partition_header_t::entries() {
    if (f_entries)
        return m_entries;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek((entries_start() * _root()->sector_size()));
    int l_entries = entries_count();
    m__raw_entries = new std::vector<std::string>();
    m__raw_entries->reserve(l_entries);
    m__io__raw_entries = new std::vector<kaitai::kstream*>();
    m__io__raw_entries->reserve(l_entries);
    m_entries = new std::vector<partition_entry_t*>();
    m_entries->reserve(l_entries);
    for (int i = 0; i < l_entries; i++) {
        m__raw_entries->push_back(io->read_bytes(entries_size()));
        kaitai::kstream* io__raw_entries = new kaitai::kstream(m__raw_entries->at(m__raw_entries->size() - 1));
        m__io__raw_entries->push_back(io__raw_entries);
        m_entries->push_back(new partition_entry_t(io__raw_entries, this, m__root));
    }
    io->seek(_pos);
    f_entries = true;
    return m_entries;
}

int32_t gpt_partition_table_t::sector_size() {
    if (f_sector_size)
        return m_sector_size;
    m_sector_size = 512;
    f_sector_size = true;
    return m_sector_size;
}

gpt_partition_table_t::partition_header_t* gpt_partition_table_t::primary() {
    if (f_primary)
        return m_primary;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(_root()->sector_size());
    m_primary = new partition_header_t(io, this, m__root);
    io->seek(_pos);
    f_primary = true;
    return m_primary;
}

gpt_partition_table_t::partition_header_t* gpt_partition_table_t::backup() {
    if (f_backup)
        return m_backup;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek((_io()->size() - _root()->sector_size()));
    m_backup = new partition_header_t(io, this, m__root);
    io->seek(_pos);
    f_backup = true;
    return m_backup;
}