SQLite3 database file: C++/STL parsing library

SQLite3 is a popular serverless SQL engine, implemented as a library to be used within other applications. It keeps its databases as regular disk files.

Every database file is segmented into pages. First page (starting at the very beginning) is special: it contains a file-global header which specifies some data relevant to proper parsing (i.e. format versions, size of page, etc). After the header, normal contents of the first page follow.

Each page would be of some type, and generally, they would be reached via the links starting from the first page. First page type (root_page) is always "btree_page".

KS implementation details

License: CC0-1.0

This page hosts a formal specification of SQLite3 database file 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.sqlite3", 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:
    sqlite3_t data(&ks);

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

data.len_page_mod() // => The database page size in bytes. Must be a power of two between
512 and 32768 inclusive, or the value 1 representing a page size
of 65536.

C++/STL source code to parse SQLite3 database file

sqlite3.h

#ifndef SQLITE3_H_
#define SQLITE3_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
class vlq_base128_be_t;

/**
 * SQLite3 is a popular serverless SQL engine, implemented as a library
 * to be used within other applications. It keeps its databases as
 * regular disk files.
 * 
 * Every database file is segmented into pages. First page (starting at
 * the very beginning) is special: it contains a file-global header
 * which specifies some data relevant to proper parsing (i.e. format
 * versions, size of page, etc). After the header, normal contents of
 * the first page follow.
 * 
 * Each page would be of some type, and generally, they would be
 * reached via the links starting from the first page. First page type
 * (`root_page`) is always "btree_page".
 * \sa Source
 */

class sqlite3_t : public kaitai::kstruct {

public:
    class serial_t;
    class btree_page_t;
    class cell_index_leaf_t;
    class serials_t;
    class cell_table_leaf_t;
    class cell_payload_t;
    class cell_table_interior_t;
    class cell_index_interior_t;
    class column_content_t;
    class ref_cell_t;

    enum versions_t {
        VERSIONS_LEGACY = 1,
        VERSIONS_WAL = 2
    };

    enum encodings_t {
        ENCODINGS_UTF_8 = 1,
        ENCODINGS_UTF_16LE = 2,
        ENCODINGS_UTF_16BE = 3
    };

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

private:
    void _read();

public:
    ~sqlite3_t();

    class serial_t : public kaitai::kstruct {

    public:

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

    private:
        void _read();

    public:
        ~serial_t();

    private:
        bool f_is_blob;
        bool m_is_blob;

    public:
        bool is_blob();

    private:
        bool f_is_string;
        bool m_is_string;

    public:
        bool is_string();

    private:
        bool f_len_content;
        int32_t m_len_content;
        bool n_len_content;

    public:
        bool _is_null_len_content() { len_content(); return n_len_content; };

    private:

    public:
        int32_t len_content();

    private:
        vlq_base128_be_t* m_code;
        sqlite3_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        vlq_base128_be_t* code() const { return m_code; }
        sqlite3_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class btree_page_t : public kaitai::kstruct {

    public:

        btree_page_t(kaitai::kstream* p__io, sqlite3_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~btree_page_t();

    private:
        uint8_t m_page_type;
        uint16_t m_first_freeblock;
        uint16_t m_num_cells;
        uint16_t m_ofs_cells;
        uint8_t m_num_frag_free_bytes;
        uint32_t m_right_ptr;
        bool n_right_ptr;

    public:
        bool _is_null_right_ptr() { right_ptr(); return n_right_ptr; };

    private:
        std::vector<ref_cell_t*>* m_cells;
        sqlite3_t* m__root;
        sqlite3_t* m__parent;

    public:
        uint8_t page_type() const { return m_page_type; }
        uint16_t first_freeblock() const { return m_first_freeblock; }
        uint16_t num_cells() const { return m_num_cells; }
        uint16_t ofs_cells() const { return m_ofs_cells; }
        uint8_t num_frag_free_bytes() const { return m_num_frag_free_bytes; }
        uint32_t right_ptr() const { return m_right_ptr; }
        std::vector<ref_cell_t*>* cells() const { return m_cells; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t* _parent() const { return m__parent; }
    };

    /**
     * \sa Source
     */

    class cell_index_leaf_t : public kaitai::kstruct {

    public:

        cell_index_leaf_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~cell_index_leaf_t();

    private:
        vlq_base128_be_t* m_len_payload;
        cell_payload_t* m_payload;
        sqlite3_t* m__root;
        sqlite3_t::ref_cell_t* m__parent;
        std::string m__raw_payload;
        kaitai::kstream* m__io__raw_payload;

    public:
        vlq_base128_be_t* len_payload() const { return m_len_payload; }
        cell_payload_t* payload() const { return m_payload; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::ref_cell_t* _parent() const { return m__parent; }
        std::string _raw_payload() const { return m__raw_payload; }
        kaitai::kstream* _io__raw_payload() const { return m__io__raw_payload; }
    };

    class serials_t : public kaitai::kstruct {

    public:

        serials_t(kaitai::kstream* p__io, sqlite3_t::cell_payload_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~serials_t();

    private:
        std::vector<vlq_base128_be_t*>* m_entries;
        sqlite3_t* m__root;
        sqlite3_t::cell_payload_t* m__parent;

    public:
        std::vector<vlq_base128_be_t*>* entries() const { return m_entries; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::cell_payload_t* _parent() const { return m__parent; }
    };

    /**
     * \sa Source
     */

    class cell_table_leaf_t : public kaitai::kstruct {

    public:

        cell_table_leaf_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~cell_table_leaf_t();

    private:
        vlq_base128_be_t* m_len_payload;
        vlq_base128_be_t* m_row_id;
        cell_payload_t* m_payload;
        sqlite3_t* m__root;
        sqlite3_t::ref_cell_t* m__parent;
        std::string m__raw_payload;
        kaitai::kstream* m__io__raw_payload;

    public:
        vlq_base128_be_t* len_payload() const { return m_len_payload; }
        vlq_base128_be_t* row_id() const { return m_row_id; }
        cell_payload_t* payload() const { return m_payload; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::ref_cell_t* _parent() const { return m__parent; }
        std::string _raw_payload() const { return m__raw_payload; }
        kaitai::kstream* _io__raw_payload() const { return m__io__raw_payload; }
    };

    /**
     * \sa Source
     */

    class cell_payload_t : public kaitai::kstruct {

    public:

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

    private:
        void _read();

    public:
        ~cell_payload_t();

    private:
        vlq_base128_be_t* m_len_header_and_len;
        serials_t* m_column_serials;
        std::vector<column_content_t*>* m_column_contents;
        sqlite3_t* m__root;
        kaitai::kstruct* m__parent;
        std::string m__raw_column_serials;
        kaitai::kstream* m__io__raw_column_serials;

    public:
        vlq_base128_be_t* len_header_and_len() const { return m_len_header_and_len; }
        serials_t* column_serials() const { return m_column_serials; }
        std::vector<column_content_t*>* column_contents() const { return m_column_contents; }
        sqlite3_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
        std::string _raw_column_serials() const { return m__raw_column_serials; }
        kaitai::kstream* _io__raw_column_serials() const { return m__io__raw_column_serials; }
    };

    /**
     * \sa Source
     */

    class cell_table_interior_t : public kaitai::kstruct {

    public:

        cell_table_interior_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~cell_table_interior_t();

    private:
        uint32_t m_left_child_page;
        vlq_base128_be_t* m_row_id;
        sqlite3_t* m__root;
        sqlite3_t::ref_cell_t* m__parent;

    public:
        uint32_t left_child_page() const { return m_left_child_page; }
        vlq_base128_be_t* row_id() const { return m_row_id; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::ref_cell_t* _parent() const { return m__parent; }
    };

    /**
     * \sa Source
     */

    class cell_index_interior_t : public kaitai::kstruct {

    public:

        cell_index_interior_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~cell_index_interior_t();

    private:
        uint32_t m_left_child_page;
        vlq_base128_be_t* m_len_payload;
        cell_payload_t* m_payload;
        sqlite3_t* m__root;
        sqlite3_t::ref_cell_t* m__parent;
        std::string m__raw_payload;
        kaitai::kstream* m__io__raw_payload;

    public:
        uint32_t left_child_page() const { return m_left_child_page; }
        vlq_base128_be_t* len_payload() const { return m_len_payload; }
        cell_payload_t* payload() const { return m_payload; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::ref_cell_t* _parent() const { return m__parent; }
        std::string _raw_payload() const { return m__raw_payload; }
        kaitai::kstream* _io__raw_payload() const { return m__io__raw_payload; }
    };

    class column_content_t : public kaitai::kstruct {

    public:

        column_content_t(kaitai::kstruct* p_ser, kaitai::kstream* p__io, sqlite3_t::cell_payload_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~column_content_t();

    private:
        bool f_serial_type;
        sqlite3_t::serial_t* m_serial_type;

    public:
        sqlite3_t::serial_t* serial_type();

    private:
        int32_t m_as_int;
        bool n_as_int;

    public:
        bool _is_null_as_int() { as_int(); return n_as_int; };

    private:
        double m_as_float;
        bool n_as_float;

    public:
        bool _is_null_as_float() { as_float(); return n_as_float; };

    private:
        std::string m_as_blob;
        bool n_as_blob;

    public:
        bool _is_null_as_blob() { as_blob(); return n_as_blob; };

    private:
        std::string m_as_str;
        kaitai::kstruct* m_ser;
        sqlite3_t* m__root;
        sqlite3_t::cell_payload_t* m__parent;

    public:
        int32_t as_int() const { return m_as_int; }
        double as_float() const { return m_as_float; }
        std::string as_blob() const { return m_as_blob; }
        std::string as_str() const { return m_as_str; }
        kaitai::kstruct* ser() const { return m_ser; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::cell_payload_t* _parent() const { return m__parent; }
    };

    class ref_cell_t : public kaitai::kstruct {

    public:

        ref_cell_t(kaitai::kstream* p__io, sqlite3_t::btree_page_t* p__parent = 0, sqlite3_t* p__root = 0);

    private:
        void _read();

    public:
        ~ref_cell_t();

    private:
        bool f_body;
        kaitai::kstruct* m_body;
        bool n_body;

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

    private:

    public:
        kaitai::kstruct* body();

    private:
        uint16_t m_ofs_body;
        sqlite3_t* m__root;
        sqlite3_t::btree_page_t* m__parent;

    public:
        uint16_t ofs_body() const { return m_ofs_body; }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::btree_page_t* _parent() const { return m__parent; }
    };

private:
    bool f_len_page;
    int32_t m_len_page;

public:
    int32_t len_page();

private:
    std::string m_magic;
    uint16_t m_len_page_mod;
    versions_t m_write_version;
    versions_t m_read_version;
    uint8_t m_reserved_space;
    uint8_t m_max_payload_frac;
    uint8_t m_min_payload_frac;
    uint8_t m_leaf_payload_frac;
    uint32_t m_file_change_counter;
    uint32_t m_num_pages;
    uint32_t m_first_freelist_trunk_page;
    uint32_t m_num_freelist_pages;
    uint32_t m_schema_cookie;
    uint32_t m_schema_format;
    uint32_t m_def_page_cache_size;
    uint32_t m_largest_root_page;
    encodings_t m_text_encoding;
    uint32_t m_user_version;
    uint32_t m_is_incremental_vacuum;
    uint32_t m_application_id;
    std::string m_reserved;
    uint32_t m_version_valid_for;
    uint32_t m_sqlite_version_number;
    btree_page_t* m_root_page;
    sqlite3_t* m__root;
    kaitai::kstruct* m__parent;

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

    /**
     * The database page size in bytes. Must be a power of two between
     * 512 and 32768 inclusive, or the value 1 representing a page size
     * of 65536.
     */
    uint16_t len_page_mod() const { return m_len_page_mod; }
    versions_t write_version() const { return m_write_version; }
    versions_t read_version() const { return m_read_version; }

    /**
     * Bytes of unused "reserved" space at the end of each page. Usually 0.
     */
    uint8_t reserved_space() const { return m_reserved_space; }

    /**
     * Maximum embedded payload fraction. Must be 64.
     */
    uint8_t max_payload_frac() const { return m_max_payload_frac; }

    /**
     * Minimum embedded payload fraction. Must be 32.
     */
    uint8_t min_payload_frac() const { return m_min_payload_frac; }

    /**
     * Leaf payload fraction. Must be 32.
     */
    uint8_t leaf_payload_frac() const { return m_leaf_payload_frac; }
    uint32_t file_change_counter() const { return m_file_change_counter; }

    /**
     * Size of the database file in pages. The "in-header database size".
     */
    uint32_t num_pages() const { return m_num_pages; }

    /**
     * Page number of the first freelist trunk page.
     */
    uint32_t first_freelist_trunk_page() const { return m_first_freelist_trunk_page; }

    /**
     * Total number of freelist pages.
     */
    uint32_t num_freelist_pages() const { return m_num_freelist_pages; }
    uint32_t schema_cookie() const { return m_schema_cookie; }

    /**
     * The schema format number. Supported schema formats are 1, 2, 3, and 4.
     */
    uint32_t schema_format() const { return m_schema_format; }

    /**
     * Default page cache size.
     */
    uint32_t def_page_cache_size() const { return m_def_page_cache_size; }

    /**
     * The page number of the largest root b-tree page when in auto-vacuum or incremental-vacuum modes, or zero otherwise.
     */
    uint32_t largest_root_page() const { return m_largest_root_page; }

    /**
     * The database text encoding. A value of 1 means UTF-8. A value of 2 means UTF-16le. A value of 3 means UTF-16be.
     */
    encodings_t text_encoding() const { return m_text_encoding; }

    /**
     * The "user version" as read and set by the user_version pragma.
     */
    uint32_t user_version() const { return m_user_version; }

    /**
     * True (non-zero) for incremental-vacuum mode. False (zero) otherwise.
     */
    uint32_t is_incremental_vacuum() const { return m_is_incremental_vacuum; }

    /**
     * The "Application ID" set by PRAGMA application_id.
     */
    uint32_t application_id() const { return m_application_id; }
    std::string reserved() const { return m_reserved; }
    uint32_t version_valid_for() const { return m_version_valid_for; }
    uint32_t sqlite_version_number() const { return m_sqlite_version_number; }
    btree_page_t* root_page() const { return m_root_page; }
    sqlite3_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // SQLITE3_H_

sqlite3.cpp

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

#include "sqlite3.h"


#include "vlq_base128_be.h"

sqlite3_t::sqlite3_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    f_len_page = false;
    _read();
}

void sqlite3_t::_read() {
    m_magic = m__io->ensure_fixed_contents(std::string("\x53\x51\x4C\x69\x74\x65\x20\x66\x6F\x72\x6D\x61\x74\x20\x33\x00", 16));
    m_len_page_mod = m__io->read_u2be();
    m_write_version = static_cast<sqlite3_t::versions_t>(m__io->read_u1());
    m_read_version = static_cast<sqlite3_t::versions_t>(m__io->read_u1());
    m_reserved_space = m__io->read_u1();
    m_max_payload_frac = m__io->read_u1();
    m_min_payload_frac = m__io->read_u1();
    m_leaf_payload_frac = m__io->read_u1();
    m_file_change_counter = m__io->read_u4be();
    m_num_pages = m__io->read_u4be();
    m_first_freelist_trunk_page = m__io->read_u4be();
    m_num_freelist_pages = m__io->read_u4be();
    m_schema_cookie = m__io->read_u4be();
    m_schema_format = m__io->read_u4be();
    m_def_page_cache_size = m__io->read_u4be();
    m_largest_root_page = m__io->read_u4be();
    m_text_encoding = static_cast<sqlite3_t::encodings_t>(m__io->read_u4be());
    m_user_version = m__io->read_u4be();
    m_is_incremental_vacuum = m__io->read_u4be();
    m_application_id = m__io->read_u4be();
    m_reserved = m__io->read_bytes(20);
    m_version_valid_for = m__io->read_u4be();
    m_sqlite_version_number = m__io->read_u4be();
    m_root_page = new btree_page_t(m__io, this, m__root);
}

sqlite3_t::~sqlite3_t() {
    delete m_root_page;
}

sqlite3_t::serial_t::serial_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_is_blob = false;
    f_is_string = false;
    f_len_content = false;
    _read();
}

void sqlite3_t::serial_t::_read() {
    m_code = new vlq_base128_be_t(m__io);
}

sqlite3_t::serial_t::~serial_t() {
    delete m_code;
}

bool sqlite3_t::serial_t::is_blob() {
    if (f_is_blob)
        return m_is_blob;
    m_is_blob =  ((code()->value() >= 12) && (kaitai::kstream::mod(code()->value(), 2) == 0)) ;
    f_is_blob = true;
    return m_is_blob;
}

bool sqlite3_t::serial_t::is_string() {
    if (f_is_string)
        return m_is_string;
    m_is_string =  ((code()->value() >= 13) && (kaitai::kstream::mod(code()->value(), 2) == 1)) ;
    f_is_string = true;
    return m_is_string;
}

int32_t sqlite3_t::serial_t::len_content() {
    if (f_len_content)
        return m_len_content;
    n_len_content = true;
    if (code()->value() >= 12) {
        n_len_content = false;
        m_len_content = ((code()->value() - 12) / 2);
    }
    f_len_content = true;
    return m_len_content;
}

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

void sqlite3_t::btree_page_t::_read() {
    m_page_type = m__io->read_u1();
    m_first_freeblock = m__io->read_u2be();
    m_num_cells = m__io->read_u2be();
    m_ofs_cells = m__io->read_u2be();
    m_num_frag_free_bytes = m__io->read_u1();
    n_right_ptr = true;
    if ( ((page_type() == 2) || (page_type() == 5)) ) {
        n_right_ptr = false;
        m_right_ptr = m__io->read_u4be();
    }
    int l_cells = num_cells();
    m_cells = new std::vector<ref_cell_t*>();
    m_cells->reserve(l_cells);
    for (int i = 0; i < l_cells; i++) {
        m_cells->push_back(new ref_cell_t(m__io, this, m__root));
    }
}

sqlite3_t::btree_page_t::~btree_page_t() {
    if (!n_right_ptr) {
    }
    for (std::vector<ref_cell_t*>::iterator it = m_cells->begin(); it != m_cells->end(); ++it) {
        delete *it;
    }
    delete m_cells;
}

sqlite3_t::cell_index_leaf_t::cell_index_leaf_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void sqlite3_t::cell_index_leaf_t::_read() {
    m_len_payload = new vlq_base128_be_t(m__io);
    m__raw_payload = m__io->read_bytes(len_payload()->value());
    m__io__raw_payload = new kaitai::kstream(m__raw_payload);
    m_payload = new cell_payload_t(m__io__raw_payload, this, m__root);
}

sqlite3_t::cell_index_leaf_t::~cell_index_leaf_t() {
    delete m_len_payload;
    delete m__io__raw_payload;
    delete m_payload;
}

sqlite3_t::serials_t::serials_t(kaitai::kstream* p__io, sqlite3_t::cell_payload_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void sqlite3_t::serials_t::_read() {
    m_entries = new std::vector<vlq_base128_be_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(new vlq_base128_be_t(m__io));
            i++;
        }
    }
}

sqlite3_t::serials_t::~serials_t() {
    for (std::vector<vlq_base128_be_t*>::iterator it = m_entries->begin(); it != m_entries->end(); ++it) {
        delete *it;
    }
    delete m_entries;
}

sqlite3_t::cell_table_leaf_t::cell_table_leaf_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void sqlite3_t::cell_table_leaf_t::_read() {
    m_len_payload = new vlq_base128_be_t(m__io);
    m_row_id = new vlq_base128_be_t(m__io);
    m__raw_payload = m__io->read_bytes(len_payload()->value());
    m__io__raw_payload = new kaitai::kstream(m__raw_payload);
    m_payload = new cell_payload_t(m__io__raw_payload, this, m__root);
}

sqlite3_t::cell_table_leaf_t::~cell_table_leaf_t() {
    delete m_len_payload;
    delete m_row_id;
    delete m__io__raw_payload;
    delete m_payload;
}

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

void sqlite3_t::cell_payload_t::_read() {
    m_len_header_and_len = new vlq_base128_be_t(m__io);
    m__raw_column_serials = m__io->read_bytes((len_header_and_len()->value() - 1));
    m__io__raw_column_serials = new kaitai::kstream(m__raw_column_serials);
    m_column_serials = new serials_t(m__io__raw_column_serials, this, m__root);
    int l_column_contents = column_serials()->entries()->size();
    m_column_contents = new std::vector<column_content_t*>();
    m_column_contents->reserve(l_column_contents);
    for (int i = 0; i < l_column_contents; i++) {
        m_column_contents->push_back(new column_content_t(column_serials()->entries()->at(i), m__io, this, m__root));
    }
}

sqlite3_t::cell_payload_t::~cell_payload_t() {
    delete m_len_header_and_len;
    delete m__io__raw_column_serials;
    delete m_column_serials;
    for (std::vector<column_content_t*>::iterator it = m_column_contents->begin(); it != m_column_contents->end(); ++it) {
        delete *it;
    }
    delete m_column_contents;
}

sqlite3_t::cell_table_interior_t::cell_table_interior_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void sqlite3_t::cell_table_interior_t::_read() {
    m_left_child_page = m__io->read_u4be();
    m_row_id = new vlq_base128_be_t(m__io);
}

sqlite3_t::cell_table_interior_t::~cell_table_interior_t() {
    delete m_row_id;
}

sqlite3_t::cell_index_interior_t::cell_index_interior_t(kaitai::kstream* p__io, sqlite3_t::ref_cell_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void sqlite3_t::cell_index_interior_t::_read() {
    m_left_child_page = m__io->read_u4be();
    m_len_payload = new vlq_base128_be_t(m__io);
    m__raw_payload = m__io->read_bytes(len_payload()->value());
    m__io__raw_payload = new kaitai::kstream(m__raw_payload);
    m_payload = new cell_payload_t(m__io__raw_payload, this, m__root);
}

sqlite3_t::cell_index_interior_t::~cell_index_interior_t() {
    delete m_len_payload;
    delete m__io__raw_payload;
    delete m_payload;
}

sqlite3_t::column_content_t::column_content_t(kaitai::kstruct* p_ser, kaitai::kstream* p__io, sqlite3_t::cell_payload_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_ser = p_ser;
    f_serial_type = false;
    _read();
}

void sqlite3_t::column_content_t::_read() {
    n_as_int = true;
    if ( ((serial_type()->code()->value() >= 1) && (serial_type()->code()->value() <= 6)) ) {
        n_as_int = false;
        n_as_int = true;
        switch (serial_type()->code()->value()) {
        case 4: {
            n_as_int = false;
            m_as_int = m__io->read_u4be();
            break;
        }
        case 6: {
            n_as_int = false;
            m_as_int = m__io->read_u8be();
            break;
        }
        case 1: {
            n_as_int = false;
            m_as_int = m__io->read_u1();
            break;
        }
        case 3: {
            n_as_int = false;
            m_as_int = m__io->read_bits_int(24);
            break;
        }
        case 5: {
            n_as_int = false;
            m_as_int = m__io->read_bits_int(48);
            break;
        }
        case 2: {
            n_as_int = false;
            m_as_int = m__io->read_u2be();
            break;
        }
        }
    }
    n_as_float = true;
    if (serial_type()->code()->value() == 7) {
        n_as_float = false;
        m_as_float = m__io->read_f8be();
    }
    n_as_blob = true;
    if (serial_type()->is_blob()) {
        n_as_blob = false;
        m_as_blob = m__io->read_bytes(serial_type()->len_content());
    }
    m_as_str = kaitai::kstream::bytes_to_str(m__io->read_bytes(serial_type()->len_content()), std::string("UTF-8"));
}

sqlite3_t::column_content_t::~column_content_t() {
    if (!n_as_int) {
    }
    if (!n_as_float) {
    }
    if (!n_as_blob) {
    }
}

sqlite3_t::serial_t* sqlite3_t::column_content_t::serial_type() {
    if (f_serial_type)
        return m_serial_type;
    m_serial_type = static_cast<serial_t*>(ser());
    f_serial_type = true;
    return m_serial_type;
}

sqlite3_t::ref_cell_t::ref_cell_t(kaitai::kstream* p__io, sqlite3_t::btree_page_t* p__parent, sqlite3_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_body = false;
    _read();
}

void sqlite3_t::ref_cell_t::_read() {
    m_ofs_body = m__io->read_u2be();
}

sqlite3_t::ref_cell_t::~ref_cell_t() {
    if (f_body && !n_body) {
        delete m_body;
    }
}

kaitai::kstruct* sqlite3_t::ref_cell_t::body() {
    if (f_body)
        return m_body;
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_body());
    n_body = true;
    switch (_parent()->page_type()) {
    case 13: {
        n_body = false;
        m_body = new cell_table_leaf_t(m__io, this, m__root);
        break;
    }
    case 5: {
        n_body = false;
        m_body = new cell_table_interior_t(m__io, this, m__root);
        break;
    }
    case 10: {
        n_body = false;
        m_body = new cell_index_leaf_t(m__io, this, m__root);
        break;
    }
    case 2: {
        n_body = false;
        m_body = new cell_index_interior_t(m__io, this, m__root);
        break;
    }
    }
    m__io->seek(_pos);
    f_body = true;
    return m_body;
}

int32_t sqlite3_t::len_page() {
    if (f_len_page)
        return m_len_page;
    m_len_page = ((len_page_mod() == 1) ? (65536) : (len_page_mod()));
    f_len_page = true;
    return m_len_page;
}