MBR (Master Boot Record) partition table: C++11/STL parsing library

MBR (Master Boot Record) partition table is a traditional way of MS-DOS to partition larger hard disc drives into distinct partitions.

This table is stored in the end of the boot sector (first sector) of the drive, after the bootstrap code. Original DOS 2.0 specification allowed only 4 partitions per disc, but DOS 3.2 introduced concept of "extended partitions", which work as nested extra "boot records" which are pointed to by original ("primary") partitions in MBR.

This page hosts a formal specification of MBR (Master Boot Record) partition table 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.bin", 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:
    mbr_partition_table_t data(&ks);
    

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

data.bootstrap_code() // => get bootstrap code

C++11/STL source code to parse MBR (Master Boot Record) partition table

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

/**
 * MBR (Master Boot Record) partition table is a traditional way of
 * MS-DOS to partition larger hard disc drives into distinct
 * partitions.
 * 
 * This table is stored in the end of the boot sector (first sector) of
 * the drive, after the bootstrap code. Original DOS 2.0 specification
 * allowed only 4 partitions per disc, but DOS 3.2 introduced concept
 * of "extended partitions", which work as nested extra "boot records"
 * which are pointed to by original ("primary") partitions in MBR.
 */

class mbr_partition_table_t : public kaitai::kstruct {

public:
    class partition_entry_t;
    class chs_t;

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

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

public:
    ~mbr_partition_table_t();

    class partition_entry_t : public kaitai::kstruct {

    public:

        partition_entry_t(kaitai::kstream* p__io, mbr_partition_table_t* p__parent = nullptr, mbr_partition_table_t* p__root = nullptr);

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

    public:
        ~partition_entry_t();

    private:
        uint8_t m_status;
        std::unique_ptr<chs_t> m_chs_start;
        uint8_t m_partition_type;
        std::unique_ptr<chs_t> m_chs_end;
        uint32_t m_lba_start;
        uint32_t m_num_sectors;
        mbr_partition_table_t* m__root;
        mbr_partition_table_t* m__parent;

    public:
        uint8_t status() const { return m_status; }
        chs_t* chs_start() const { return m_chs_start.get(); }
        uint8_t partition_type() const { return m_partition_type; }
        chs_t* chs_end() const { return m_chs_end.get(); }
        uint32_t lba_start() const { return m_lba_start; }
        uint32_t num_sectors() const { return m_num_sectors; }
        mbr_partition_table_t* _root() const { return m__root; }
        mbr_partition_table_t* _parent() const { return m__parent; }
    };

    class chs_t : public kaitai::kstruct {

    public:

        chs_t(kaitai::kstream* p__io, mbr_partition_table_t::partition_entry_t* p__parent = nullptr, mbr_partition_table_t* p__root = nullptr);

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

    public:
        ~chs_t();

    private:
        bool f_sector;
        int32_t m_sector;

    public:
        int32_t sector();

    private:
        bool f_cylinder;
        int32_t m_cylinder;

    public:
        int32_t cylinder();

    private:
        uint8_t m_head;
        uint8_t m_b2;
        uint8_t m_b3;
        mbr_partition_table_t* m__root;
        mbr_partition_table_t::partition_entry_t* m__parent;

    public:
        uint8_t head() const { return m_head; }
        uint8_t b2() const { return m_b2; }
        uint8_t b3() const { return m_b3; }
        mbr_partition_table_t* _root() const { return m__root; }
        mbr_partition_table_t::partition_entry_t* _parent() const { return m__parent; }
    };

private:
    std::string m_bootstrap_code;
    std::unique_ptr<std::vector<std::unique_ptr<partition_entry_t>>> m_partitions;
    std::string m_boot_signature;
    mbr_partition_table_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::string bootstrap_code() const { return m_bootstrap_code; }
    std::vector<std::unique_ptr<partition_entry_t>>* partitions() const { return m_partitions.get(); }
    std::string boot_signature() const { return m_boot_signature; }
    mbr_partition_table_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

mbr_partition_table.cpp

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

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

mbr_partition_table_t::mbr_partition_table_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mbr_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_partitions = nullptr;
    _read();
}

void mbr_partition_table_t::_read() {
    m_bootstrap_code = m__io->read_bytes(446);
    m_partitions = std::unique_ptr<std::vector<std::unique_ptr<partition_entry_t>>>(new std::vector<std::unique_ptr<partition_entry_t>>());
    const int l_partitions = 4;
    for (int i = 0; i < l_partitions; i++) {
        m_partitions->push_back(std::move(std::unique_ptr<partition_entry_t>(new partition_entry_t(m__io, this, m__root))));
    }
    m_boot_signature = m__io->read_bytes(2);
    if (!(boot_signature() == std::string("\x55\xAA", 2))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x55\xAA", 2), boot_signature(), _io(), std::string("/seq/2"));
    }
}

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

void mbr_partition_table_t::_clean_up() {
}

mbr_partition_table_t::partition_entry_t::partition_entry_t(kaitai::kstream* p__io, mbr_partition_table_t* p__parent, mbr_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_chs_start = nullptr;
    m_chs_end = nullptr;
    _read();
}

void mbr_partition_table_t::partition_entry_t::_read() {
    m_status = m__io->read_u1();
    m_chs_start = std::unique_ptr<chs_t>(new chs_t(m__io, this, m__root));
    m_partition_type = m__io->read_u1();
    m_chs_end = std::unique_ptr<chs_t>(new chs_t(m__io, this, m__root));
    m_lba_start = m__io->read_u4le();
    m_num_sectors = m__io->read_u4le();
}

mbr_partition_table_t::partition_entry_t::~partition_entry_t() {
    _clean_up();
}

void mbr_partition_table_t::partition_entry_t::_clean_up() {
}

mbr_partition_table_t::chs_t::chs_t(kaitai::kstream* p__io, mbr_partition_table_t::partition_entry_t* p__parent, mbr_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_sector = false;
    f_cylinder = false;
    _read();
}

void mbr_partition_table_t::chs_t::_read() {
    m_head = m__io->read_u1();
    m_b2 = m__io->read_u1();
    m_b3 = m__io->read_u1();
}

mbr_partition_table_t::chs_t::~chs_t() {
    _clean_up();
}

void mbr_partition_table_t::chs_t::_clean_up() {
}

int32_t mbr_partition_table_t::chs_t::sector() {
    if (f_sector)
        return m_sector;
    m_sector = (b2() & 63);
    f_sector = true;
    return m_sector;
}

int32_t mbr_partition_table_t::chs_t::cylinder() {
    if (f_cylinder)
        return m_cylinder;
    m_cylinder = (b3() + ((b2() & 192) << 2));
    f_cylinder = true;
    return m_cylinder;
}