cramfs: C++98/STL parsing library

KS implementation details

License: MIT

References

This page hosts a formal specification of cramfs 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++98/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.cramfs", 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:
    cramfs_t data(&ks);
    

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

data.super_block() // => get super block

C++98/STL source code to parse cramfs

cramfs.h

#ifndef CRAMFS_H_
#define CRAMFS_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 < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif

class cramfs_t : public kaitai::kstruct {

public:
    class super_block_struct_t;
    class chunked_data_inode_t;
    class inode_t;
    class dir_inode_t;
    class info_t;

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

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

public:
    ~cramfs_t();

    class super_block_struct_t : public kaitai::kstruct {

    public:

        super_block_struct_t(kaitai::kstream* p__io, cramfs_t* p__parent = 0, cramfs_t* p__root = 0);

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

    public:
        ~super_block_struct_t();

    private:
        bool f_flag_fsid_v2;
        int32_t m_flag_fsid_v2;

    public:
        int32_t flag_fsid_v2();

    private:
        bool f_flag_holes;
        int32_t m_flag_holes;

    public:
        int32_t flag_holes();

    private:
        bool f_flag_wrong_signature;
        int32_t m_flag_wrong_signature;

    public:
        int32_t flag_wrong_signature();

    private:
        bool f_flag_sorted_dirs;
        int32_t m_flag_sorted_dirs;

    public:
        int32_t flag_sorted_dirs();

    private:
        bool f_flag_shifted_root_offset;
        int32_t m_flag_shifted_root_offset;

    public:
        int32_t flag_shifted_root_offset();

    private:
        std::string m_magic;
        uint32_t m_size;
        uint32_t m_flags;
        uint32_t m_future;
        std::string m_signature;
        info_t* m_fsid;
        std::string m_name;
        inode_t* m_root;
        cramfs_t* m__root;
        cramfs_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint32_t size() const { return m_size; }
        uint32_t flags() const { return m_flags; }
        uint32_t future() const { return m_future; }
        std::string signature() const { return m_signature; }
        info_t* fsid() const { return m_fsid; }
        std::string name() const { return m_name; }
        inode_t* root() const { return m_root; }
        cramfs_t* _root() const { return m__root; }
        cramfs_t* _parent() const { return m__parent; }
    };

    class chunked_data_inode_t : public kaitai::kstruct {

    public:

        chunked_data_inode_t(kaitai::kstream* p__io, cramfs_t::inode_t* p__parent = 0, cramfs_t* p__root = 0);

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

    public:
        ~chunked_data_inode_t();

    private:
        std::vector<uint32_t>* m_block_end_index;
        std::string m_raw_blocks;
        cramfs_t* m__root;
        cramfs_t::inode_t* m__parent;

    public:
        std::vector<uint32_t>* block_end_index() const { return m_block_end_index; }
        std::string raw_blocks() const { return m_raw_blocks; }
        cramfs_t* _root() const { return m__root; }
        cramfs_t::inode_t* _parent() const { return m__parent; }
    };

    class inode_t : public kaitai::kstruct {

    public:

        enum file_type_t {
            FILE_TYPE_FIFO = 1,
            FILE_TYPE_CHRDEV = 2,
            FILE_TYPE_DIR = 4,
            FILE_TYPE_BLKDEV = 6,
            FILE_TYPE_REG_FILE = 8,
            FILE_TYPE_SYMLINK = 10,
            FILE_TYPE_SOCKET = 12
        };

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

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

    public:
        ~inode_t();

    private:
        bool f_attr;
        int32_t m_attr;

    public:
        int32_t attr();

    private:
        bool f_as_reg_file;
        chunked_data_inode_t* m_as_reg_file;

    public:
        chunked_data_inode_t* as_reg_file();

    private:
        bool f_perm_u;
        int32_t m_perm_u;

    public:
        int32_t perm_u();

    private:
        bool f_as_symlink;
        chunked_data_inode_t* m_as_symlink;

    public:
        chunked_data_inode_t* as_symlink();

    private:
        bool f_perm_o;
        int32_t m_perm_o;

    public:
        int32_t perm_o();

    private:
        bool f_size;
        int32_t m_size;

    public:
        int32_t size();

    private:
        bool f_gid;
        int32_t m_gid;

    public:
        int32_t gid();

    private:
        bool f_perm_g;
        int32_t m_perm_g;

    public:
        int32_t perm_g();

    private:
        bool f_namelen;
        int32_t m_namelen;

    public:
        int32_t namelen();

    private:
        bool f_as_dir;
        dir_inode_t* m_as_dir;

    public:
        dir_inode_t* as_dir();

    private:
        bool f_type;
        file_type_t m_type;

    public:
        file_type_t type();

    private:
        bool f_offset;
        int32_t m_offset;

    public:
        int32_t offset();

    private:
        uint16_t m_mode;
        uint16_t m_uid;
        uint32_t m_size_gid;
        uint32_t m_namelen_offset;
        std::string m_name;
        cramfs_t* m__root;
        kaitai::kstruct* m__parent;
        std::string m__raw_as_dir;
        kaitai::kstream* m__io__raw_as_dir;

    public:
        uint16_t mode() const { return m_mode; }
        uint16_t uid() const { return m_uid; }
        uint32_t size_gid() const { return m_size_gid; }
        uint32_t namelen_offset() const { return m_namelen_offset; }
        std::string name() const { return m_name; }
        cramfs_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
        std::string _raw_as_dir() const { return m__raw_as_dir; }
        kaitai::kstream* _io__raw_as_dir() const { return m__io__raw_as_dir; }
    };

    class dir_inode_t : public kaitai::kstruct {

    public:

        dir_inode_t(kaitai::kstream* p__io, cramfs_t::inode_t* p__parent = 0, cramfs_t* p__root = 0);

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

    public:
        ~dir_inode_t();

    private:
        std::vector<inode_t*>* m_children;
        bool n_children;

    public:
        bool _is_null_children() { children(); return n_children; };

    private:
        cramfs_t* m__root;
        cramfs_t::inode_t* m__parent;

    public:
        std::vector<inode_t*>* children() const { return m_children; }
        cramfs_t* _root() const { return m__root; }
        cramfs_t::inode_t* _parent() const { return m__parent; }
    };

    class info_t : public kaitai::kstruct {

    public:

        info_t(kaitai::kstream* p__io, cramfs_t::super_block_struct_t* p__parent = 0, cramfs_t* p__root = 0);

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

    public:
        ~info_t();

    private:
        uint32_t m_crc;
        uint32_t m_edition;
        uint32_t m_blocks;
        uint32_t m_files;
        cramfs_t* m__root;
        cramfs_t::super_block_struct_t* m__parent;

    public:
        uint32_t crc() const { return m_crc; }
        uint32_t edition() const { return m_edition; }
        uint32_t blocks() const { return m_blocks; }
        uint32_t files() const { return m_files; }
        cramfs_t* _root() const { return m__root; }
        cramfs_t::super_block_struct_t* _parent() const { return m__parent; }
    };

private:
    bool f_page_size;
    int32_t m_page_size;

public:
    int32_t page_size();

private:
    super_block_struct_t* m_super_block;
    cramfs_t* m__root;
    kaitai::kstruct* m__parent;

public:
    super_block_struct_t* super_block() const { return m_super_block; }
    cramfs_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // CRAMFS_H_

cramfs.cpp

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

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

cramfs_t::cramfs_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, cramfs_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_super_block = 0;
    f_page_size = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void cramfs_t::_read() {
    m_super_block = new super_block_struct_t(m__io, this, m__root);
}

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

void cramfs_t::_clean_up() {
    if (m_super_block) {
        delete m_super_block; m_super_block = 0;
    }
}

cramfs_t::super_block_struct_t::super_block_struct_t(kaitai::kstream* p__io, cramfs_t* p__parent, cramfs_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_fsid = 0;
    m_root = 0;
    f_flag_fsid_v2 = false;
    f_flag_holes = false;
    f_flag_wrong_signature = false;
    f_flag_sorted_dirs = false;
    f_flag_shifted_root_offset = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void cramfs_t::super_block_struct_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x45\x3D\xCD\x28", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x45\x3D\xCD\x28", 4), magic(), _io(), std::string("/types/super_block_struct/seq/0"));
    }
    m_size = m__io->read_u4le();
    m_flags = m__io->read_u4le();
    m_future = m__io->read_u4le();
    m_signature = m__io->read_bytes(16);
    if (!(signature() == std::string("\x43\x6F\x6D\x70\x72\x65\x73\x73\x65\x64\x20\x52\x4F\x4D\x46\x53", 16))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x43\x6F\x6D\x70\x72\x65\x73\x73\x65\x64\x20\x52\x4F\x4D\x46\x53", 16), signature(), _io(), std::string("/types/super_block_struct/seq/4"));
    }
    m_fsid = new info_t(m__io, this, m__root);
    m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(16), std::string("ASCII"));
    m_root = new inode_t(m__io, this, m__root);
}

cramfs_t::super_block_struct_t::~super_block_struct_t() {
    _clean_up();
}

void cramfs_t::super_block_struct_t::_clean_up() {
    if (m_fsid) {
        delete m_fsid; m_fsid = 0;
    }
    if (m_root) {
        delete m_root; m_root = 0;
    }
}

int32_t cramfs_t::super_block_struct_t::flag_fsid_v2() {
    if (f_flag_fsid_v2)
        return m_flag_fsid_v2;
    m_flag_fsid_v2 = ((flags() >> 0) & 1);
    f_flag_fsid_v2 = true;
    return m_flag_fsid_v2;
}

int32_t cramfs_t::super_block_struct_t::flag_holes() {
    if (f_flag_holes)
        return m_flag_holes;
    m_flag_holes = ((flags() >> 8) & 1);
    f_flag_holes = true;
    return m_flag_holes;
}

int32_t cramfs_t::super_block_struct_t::flag_wrong_signature() {
    if (f_flag_wrong_signature)
        return m_flag_wrong_signature;
    m_flag_wrong_signature = ((flags() >> 9) & 1);
    f_flag_wrong_signature = true;
    return m_flag_wrong_signature;
}

int32_t cramfs_t::super_block_struct_t::flag_sorted_dirs() {
    if (f_flag_sorted_dirs)
        return m_flag_sorted_dirs;
    m_flag_sorted_dirs = ((flags() >> 1) & 1);
    f_flag_sorted_dirs = true;
    return m_flag_sorted_dirs;
}

int32_t cramfs_t::super_block_struct_t::flag_shifted_root_offset() {
    if (f_flag_shifted_root_offset)
        return m_flag_shifted_root_offset;
    m_flag_shifted_root_offset = ((flags() >> 10) & 1);
    f_flag_shifted_root_offset = true;
    return m_flag_shifted_root_offset;
}

cramfs_t::chunked_data_inode_t::chunked_data_inode_t(kaitai::kstream* p__io, cramfs_t::inode_t* p__parent, cramfs_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_block_end_index = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void cramfs_t::chunked_data_inode_t::_read() {
    int l_block_end_index = (((_parent()->size() + _root()->page_size()) - 1) / _root()->page_size());
    m_block_end_index = new std::vector<uint32_t>();
    m_block_end_index->reserve(l_block_end_index);
    for (int i = 0; i < l_block_end_index; i++) {
        m_block_end_index->push_back(m__io->read_u4le());
    }
    m_raw_blocks = m__io->read_bytes_full();
}

cramfs_t::chunked_data_inode_t::~chunked_data_inode_t() {
    _clean_up();
}

void cramfs_t::chunked_data_inode_t::_clean_up() {
    if (m_block_end_index) {
        delete m_block_end_index; m_block_end_index = 0;
    }
}

cramfs_t::inode_t::inode_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, cramfs_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_as_reg_file = 0;
    m_as_symlink = 0;
    m_as_dir = 0;
    m__io__raw_as_dir = 0;
    f_attr = false;
    f_as_reg_file = false;
    f_perm_u = false;
    f_as_symlink = false;
    f_perm_o = false;
    f_size = false;
    f_gid = false;
    f_perm_g = false;
    f_namelen = false;
    f_as_dir = false;
    f_type = false;
    f_offset = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void cramfs_t::inode_t::_read() {
    m_mode = m__io->read_u2le();
    m_uid = m__io->read_u2le();
    m_size_gid = m__io->read_u4le();
    m_namelen_offset = m__io->read_u4le();
    m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(namelen()), std::string("utf-8"));
}

cramfs_t::inode_t::~inode_t() {
    _clean_up();
}

void cramfs_t::inode_t::_clean_up() {
    if (f_as_reg_file) {
        if (m_as_reg_file) {
            delete m_as_reg_file; m_as_reg_file = 0;
        }
    }
    if (f_as_symlink) {
        if (m_as_symlink) {
            delete m_as_symlink; m_as_symlink = 0;
        }
    }
    if (f_as_dir) {
        if (m__io__raw_as_dir) {
            delete m__io__raw_as_dir; m__io__raw_as_dir = 0;
        }
        if (m_as_dir) {
            delete m_as_dir; m_as_dir = 0;
        }
    }
}

int32_t cramfs_t::inode_t::attr() {
    if (f_attr)
        return m_attr;
    m_attr = ((mode() >> 9) & 7);
    f_attr = true;
    return m_attr;
}

cramfs_t::chunked_data_inode_t* cramfs_t::inode_t::as_reg_file() {
    if (f_as_reg_file)
        return m_as_reg_file;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(offset());
    m_as_reg_file = new chunked_data_inode_t(io, this, m__root);
    io->seek(_pos);
    f_as_reg_file = true;
    return m_as_reg_file;
}

int32_t cramfs_t::inode_t::perm_u() {
    if (f_perm_u)
        return m_perm_u;
    m_perm_u = ((mode() >> 6) & 7);
    f_perm_u = true;
    return m_perm_u;
}

cramfs_t::chunked_data_inode_t* cramfs_t::inode_t::as_symlink() {
    if (f_as_symlink)
        return m_as_symlink;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(offset());
    m_as_symlink = new chunked_data_inode_t(io, this, m__root);
    io->seek(_pos);
    f_as_symlink = true;
    return m_as_symlink;
}

int32_t cramfs_t::inode_t::perm_o() {
    if (f_perm_o)
        return m_perm_o;
    m_perm_o = (mode() & 7);
    f_perm_o = true;
    return m_perm_o;
}

int32_t cramfs_t::inode_t::size() {
    if (f_size)
        return m_size;
    m_size = (size_gid() & 16777215);
    f_size = true;
    return m_size;
}

int32_t cramfs_t::inode_t::gid() {
    if (f_gid)
        return m_gid;
    m_gid = (size_gid() >> 24);
    f_gid = true;
    return m_gid;
}

int32_t cramfs_t::inode_t::perm_g() {
    if (f_perm_g)
        return m_perm_g;
    m_perm_g = ((mode() >> 3) & 7);
    f_perm_g = true;
    return m_perm_g;
}

int32_t cramfs_t::inode_t::namelen() {
    if (f_namelen)
        return m_namelen;
    m_namelen = ((namelen_offset() & 63) << 2);
    f_namelen = true;
    return m_namelen;
}

cramfs_t::dir_inode_t* cramfs_t::inode_t::as_dir() {
    if (f_as_dir)
        return m_as_dir;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(offset());
    m__raw_as_dir = io->read_bytes(size());
    m__io__raw_as_dir = new kaitai::kstream(m__raw_as_dir);
    m_as_dir = new dir_inode_t(m__io__raw_as_dir, this, m__root);
    io->seek(_pos);
    f_as_dir = true;
    return m_as_dir;
}

cramfs_t::inode_t::file_type_t cramfs_t::inode_t::type() {
    if (f_type)
        return m_type;
    m_type = static_cast<cramfs_t::inode_t::file_type_t>(((mode() >> 12) & 15));
    f_type = true;
    return m_type;
}

int32_t cramfs_t::inode_t::offset() {
    if (f_offset)
        return m_offset;
    m_offset = (((namelen_offset() >> 6) & 67108863) << 2);
    f_offset = true;
    return m_offset;
}

cramfs_t::dir_inode_t::dir_inode_t(kaitai::kstream* p__io, cramfs_t::inode_t* p__parent, cramfs_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_children = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void cramfs_t::dir_inode_t::_read() {
    n_children = true;
    if (_io()->size() > 0) {
        n_children = false;
        m_children = new std::vector<inode_t*>();
        {
            int i = 0;
            while (!m__io->is_eof()) {
                m_children->push_back(new inode_t(m__io, this, m__root));
                i++;
            }
        }
    }
}

cramfs_t::dir_inode_t::~dir_inode_t() {
    _clean_up();
}

void cramfs_t::dir_inode_t::_clean_up() {
    if (!n_children) {
        if (m_children) {
            for (std::vector<inode_t*>::iterator it = m_children->begin(); it != m_children->end(); ++it) {
                delete *it;
            }
            delete m_children; m_children = 0;
        }
    }
}

cramfs_t::info_t::info_t(kaitai::kstream* p__io, cramfs_t::super_block_struct_t* p__parent, cramfs_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void cramfs_t::info_t::_read() {
    m_crc = m__io->read_u4le();
    m_edition = m__io->read_u4le();
    m_blocks = m__io->read_u4le();
    m_files = m__io->read_u4le();
}

cramfs_t::info_t::~info_t() {
    _clean_up();
}

void cramfs_t::info_t::_clean_up() {
}

int32_t cramfs_t::page_size() {
    if (f_page_size)
        return m_page_size;
    m_page_size = 4096;
    f_page_size = true;
    return m_page_size;
}