SQLite3 database file: C++11/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".

File extension

["sqlite", "db", "db3", "sqlite3"]

KS implementation details

License: CC0-1.0

References

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

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.["sqlite", "db", "db3", "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++11/STL source code to parse SQLite3 database file

sqlite3.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 "vlq_base128_be.h"
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 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 https://www.sqlite.org/fileformat.html 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 = nullptr, sqlite3_t* p__root = nullptr);

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

public:
    ~sqlite3_t();

    class serial_t : public kaitai::kstruct {

    public:

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

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

    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:
        std::unique_ptr<vlq_base128_be_t> m_code;
        sqlite3_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        vlq_base128_be_t* code() const { return m_code.get(); }
        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 = nullptr, sqlite3_t* p__root = nullptr);

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

    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::unique_ptr<std::vector<std::unique_ptr<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<std::unique_ptr<ref_cell_t>>* cells() const { return m_cells.get(); }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://www.sqlite.org/fileformat.html#b_tree_pages 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 = nullptr, sqlite3_t* p__root = nullptr);

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

    public:
        ~cell_index_leaf_t();

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

    public:
        vlq_base128_be_t* len_payload() const { return m_len_payload.get(); }
        cell_payload_t* payload() const { return m_payload.get(); }
        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.get(); }
    };

    class serials_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~serials_t();

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

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

    /**
     * \sa https://www.sqlite.org/fileformat.html#b_tree_pages 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 = nullptr, sqlite3_t* p__root = nullptr);

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

    public:
        ~cell_table_leaf_t();

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

    public:
        vlq_base128_be_t* len_payload() const { return m_len_payload.get(); }
        vlq_base128_be_t* row_id() const { return m_row_id.get(); }
        cell_payload_t* payload() const { return m_payload.get(); }
        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.get(); }
    };

    /**
     * \sa https://sqlite.org/fileformat2.html#record_format Source
     */

    class cell_payload_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~cell_payload_t();

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

    public:
        vlq_base128_be_t* len_header_and_len() const { return m_len_header_and_len.get(); }
        serials_t* column_serials() const { return m_column_serials.get(); }
        std::vector<std::unique_ptr<column_content_t>>* column_contents() const { return m_column_contents.get(); }
        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.get(); }
    };

    /**
     * \sa https://www.sqlite.org/fileformat.html#b_tree_pages 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 = nullptr, sqlite3_t* p__root = nullptr);

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

    public:
        ~cell_table_interior_t();

    private:
        uint32_t m_left_child_page;
        std::unique_ptr<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.get(); }
        sqlite3_t* _root() const { return m__root; }
        sqlite3_t::ref_cell_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://www.sqlite.org/fileformat.html#b_tree_pages 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 = nullptr, sqlite3_t* p__root = nullptr);

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

    public:
        ~cell_index_interior_t();

    private:
        uint32_t m_left_child_page;
        std::unique_ptr<vlq_base128_be_t> m_len_payload;
        std::unique_ptr<cell_payload_t> m_payload;
        sqlite3_t* m__root;
        sqlite3_t::ref_cell_t* m__parent;
        std::string m__raw_payload;
        std::unique_ptr<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.get(); }
        cell_payload_t* payload() const { return m_payload.get(); }
        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.get(); }
    };

    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 = nullptr, sqlite3_t* p__root = nullptr);

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

    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 = nullptr, sqlite3_t* p__root = nullptr);

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

    public:
        ~ref_cell_t();

    private:
        bool f_body;
        std::unique_ptr<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;
    std::unique_ptr<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.get(); }
    sqlite3_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

sqlite3.cpp

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

#include "sqlite3.h"
#include "kaitai/exceptions.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;
    m_root_page = nullptr;
    f_len_page = false;
    _read();
}

void sqlite3_t::_read() {
    m_magic = m__io->read_bytes(16);
    if (!(magic() == std::string("\x53\x51\x4C\x69\x74\x65\x20\x66\x6F\x72\x6D\x61\x74\x20\x33\x00", 16))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x53\x51\x4C\x69\x74\x65\x20\x66\x6F\x72\x6D\x61\x74\x20\x33\x00", 16), magic(), _io(), std::string("/seq/0"));
    }
    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 = std::unique_ptr<btree_page_t>(new btree_page_t(m__io, this, m__root));
}

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

void sqlite3_t::_clean_up() {
}

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;
    m_code = nullptr;
    f_is_blob = false;
    f_is_string = false;
    f_len_content = false;
    _read();
}

void sqlite3_t::serial_t::_read() {
    m_code = std::unique_ptr<vlq_base128_be_t>(new vlq_base128_be_t(m__io));
}

sqlite3_t::serial_t::~serial_t() {
    _clean_up();
}

void sqlite3_t::serial_t::_clean_up() {
}

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;
    m_cells = nullptr;
    _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 = std::unique_ptr<std::vector<std::unique_ptr<ref_cell_t>>>(new std::vector<std::unique_ptr<ref_cell_t>>());
    m_cells->reserve(l_cells);
    for (int i = 0; i < l_cells; i++) {
        m_cells->push_back(std::move(std::unique_ptr<ref_cell_t>(new ref_cell_t(m__io, this, m__root))));
    }
}

sqlite3_t::btree_page_t::~btree_page_t() {
    _clean_up();
}

void sqlite3_t::btree_page_t::_clean_up() {
    if (!n_right_ptr) {
    }
}

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;
    m_len_payload = nullptr;
    m_payload = nullptr;
    m__io__raw_payload = nullptr;
    _read();
}

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

sqlite3_t::cell_index_leaf_t::~cell_index_leaf_t() {
    _clean_up();
}

void sqlite3_t::cell_index_leaf_t::_clean_up() {
}

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;
    m_entries = nullptr;
    _read();
}

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

sqlite3_t::serials_t::~serials_t() {
    _clean_up();
}

void sqlite3_t::serials_t::_clean_up() {
}

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;
    m_len_payload = nullptr;
    m_row_id = nullptr;
    m_payload = nullptr;
    m__io__raw_payload = nullptr;
    _read();
}

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

sqlite3_t::cell_table_leaf_t::~cell_table_leaf_t() {
    _clean_up();
}

void sqlite3_t::cell_table_leaf_t::_clean_up() {
}

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;
    m_len_header_and_len = nullptr;
    m_column_serials = nullptr;
    m__io__raw_column_serials = nullptr;
    m_column_contents = nullptr;
    _read();
}

void sqlite3_t::cell_payload_t::_read() {
    m_len_header_and_len = std::unique_ptr<vlq_base128_be_t>(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 = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_column_serials));
    m_column_serials = std::unique_ptr<serials_t>(new serials_t(m__io__raw_column_serials.get(), this, m__root));
    int l_column_contents = column_serials()->entries()->size();
    m_column_contents = std::unique_ptr<std::vector<std::unique_ptr<column_content_t>>>(new std::vector<std::unique_ptr<column_content_t>>());
    m_column_contents->reserve(l_column_contents);
    for (int i = 0; i < l_column_contents; i++) {
        m_column_contents->push_back(std::move(std::unique_ptr<column_content_t>(new column_content_t(column_serials()->entries()->at(i), m__io, this, m__root))));
    }
}

sqlite3_t::cell_payload_t::~cell_payload_t() {
    _clean_up();
}

void sqlite3_t::cell_payload_t::_clean_up() {
}

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;
    m_row_id = nullptr;
    _read();
}

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

sqlite3_t::cell_table_interior_t::~cell_table_interior_t() {
    _clean_up();
}

void sqlite3_t::cell_table_interior_t::_clean_up() {
}

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;
    m_len_payload = nullptr;
    m_payload = nullptr;
    m__io__raw_payload = nullptr;
    _read();
}

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

sqlite3_t::cell_index_interior_t::~cell_index_interior_t() {
    _clean_up();
}

void sqlite3_t::cell_index_interior_t::_clean_up() {
}

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_be(24);
            break;
        }
        case 5: {
            n_as_int = false;
            m_as_int = m__io->read_bits_int_be(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() {
    _clean_up();
}

void sqlite3_t::column_content_t::_clean_up() {
    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<sqlite3_t::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() {
    _clean_up();
}

void sqlite3_t::ref_cell_t::_clean_up() {
    if (f_body && !n_body) {
    }
}

kaitai::kstruct* sqlite3_t::ref_cell_t::body() {
    if (f_body)
        return m_body.get();
    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 = std::unique_ptr<cell_table_leaf_t>(new cell_table_leaf_t(m__io, this, m__root));
        break;
    }
    case 5: {
        n_body = false;
        m_body = std::unique_ptr<cell_table_interior_t>(new cell_table_interior_t(m__io, this, m__root));
        break;
    }
    case 10: {
        n_body = false;
        m_body = std::unique_ptr<cell_index_leaf_t>(new cell_index_leaf_t(m__io, this, m__root));
        break;
    }
    case 2: {
        n_body = false;
        m_body = std::unique_ptr<cell_index_interior_t>(new cell_index_interior_t(m__io, this, m__root));
        break;
    }
    }
    m__io->seek(_pos);
    f_body = true;
    return m_body.get();
}

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;
}