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.
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.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
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);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
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
#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_
// 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() {
m_block_end_index = new std::vector<uint32_t>();
const int l_block_end_index = (((_parent()->size() + _root()->page_size()) - 1) / _root()->page_size());
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;
}