Ruby's Marshal module allows serialization and deserialization of many standard and arbitrary Ruby objects in a compact binary format. It is relatively fast, available in stdlibs standard and allows conservation of language-specific properties (such as symbols or encoding-aware strings).
Feature-wise, it is comparable to other language-specific implementations, such as:
From internal perspective, serialized stream consists of a simple magic header and a record.
This page hosts a formal specification of ruby_marshal 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);
ruby_marshal_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.version() // => get version
#ifndef RUBY_MARSHAL_H_
#define RUBY_MARSHAL_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
/**
* Ruby's Marshal module allows serialization and deserialization of
* many standard and arbitrary Ruby objects in a compact binary
* format. It is relatively fast, available in stdlibs standard and
* allows conservation of language-specific properties (such as symbols
* or encoding-aware strings).
*
* Feature-wise, it is comparable to other language-specific
* implementations, such as:
*
* * Java's
* [Serializable](https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html)
* * .NET
* [BinaryFormatter](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=net-7.0)
* * Python's
* [marshal](https://docs.python.org/3/library/marshal.html),
* [pickle](https://docs.python.org/3/library/pickle.html) and
* [shelve](https://docs.python.org/3/library/shelve.html)
*
* From internal perspective, serialized stream consists of a simple
* magic header and a record.
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Stream+Format Source
*/
class ruby_marshal_t : public kaitai::kstruct {
public:
class ruby_array_t;
class bignum_t;
class ruby_struct_t;
class ruby_symbol_t;
class packed_int_t;
class pair_t;
class instance_var_t;
class record_t;
class ruby_hash_t;
class ruby_string_t;
enum codes_t {
CODES_RUBY_STRING = 34,
CODES_CONST_NIL = 48,
CODES_RUBY_SYMBOL = 58,
CODES_RUBY_SYMBOL_LINK = 59,
CODES_RUBY_OBJECT_LINK = 64,
CODES_CONST_FALSE = 70,
CODES_INSTANCE_VAR = 73,
CODES_RUBY_STRUCT = 83,
CODES_CONST_TRUE = 84,
CODES_RUBY_ARRAY = 91,
CODES_PACKED_INT = 105,
CODES_BIGNUM = 108,
CODES_RUBY_HASH = 123
};
ruby_marshal_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~ruby_marshal_t();
class ruby_array_t : public kaitai::kstruct {
public:
ruby_array_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~ruby_array_t();
private:
packed_int_t* m_num_elements;
std::vector<record_t*>* m_elements;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
packed_int_t* num_elements() const { return m_num_elements; }
std::vector<record_t*>* elements() const { return m_elements; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
/**
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Bignum Source
*/
class bignum_t : public kaitai::kstruct {
public:
bignum_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~bignum_t();
private:
uint8_t m_sign;
packed_int_t* m_len_div_2;
std::string m_body;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
/**
* A single byte containing `+` for a positive value or `-` for a negative value.
*/
uint8_t sign() const { return m_sign; }
/**
* Length of bignum body, divided by 2.
*/
packed_int_t* len_div_2() const { return m_len_div_2; }
/**
* Bytes that represent the number, see ruby-lang.org docs for reconstruction algorithm.
*/
std::string body() const { return m_body; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
/**
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Struct Source
*/
class ruby_struct_t : public kaitai::kstruct {
public:
ruby_struct_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~ruby_struct_t();
private:
record_t* m_name;
packed_int_t* m_num_members;
std::vector<pair_t*>* m_members;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
/**
* Symbol containing the name of the struct.
*/
record_t* name() const { return m_name; }
/**
* Number of members in a struct
*/
packed_int_t* num_members() const { return m_num_members; }
std::vector<pair_t*>* members() const { return m_members; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
/**
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Symbols+and+Byte+Sequence Source
*/
class ruby_symbol_t : public kaitai::kstruct {
public:
ruby_symbol_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~ruby_symbol_t();
private:
packed_int_t* m_len;
std::string m_name;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
packed_int_t* len() const { return m_len; }
std::string name() const { return m_name; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
/**
* Ruby uses sophisticated system to pack integers: first `code`
* byte either determines packing scheme or carries encoded
* immediate value (thus allowing smaller values from -123 to 122
* (inclusive) to take only one byte. There are 11 encoding schemes
* in total:
*
* * 0 is encoded specially (as 0)
* * 1..122 are encoded as immediate value with a shift
* * 123..255 are encoded with code of 0x01 and 1 extra byte
* * 0x100..0xffff are encoded with code of 0x02 and 2 extra bytes
* * 0x10000..0xffffff are encoded with code of 0x03 and 3 extra
* bytes
* * 0x1000000..0xffffffff are encoded with code of 0x04 and 4
* extra bytes
* * -123..-1 are encoded as immediate value with another shift
* * -256..-124 are encoded with code of 0xff and 1 extra byte
* * -0x10000..-257 are encoded with code of 0xfe and 2 extra bytes
* * -0x1000000..0x10001 are encoded with code of 0xfd and 3 extra
* bytes
* * -0x40000000..-0x1000001 are encoded with code of 0xfc and 4
* extra bytes
*
* Values beyond that are serialized as bignum (even if they
* technically might be not Bignum class in Ruby implementation,
* i.e. if they fit into 64 bits on a 64-bit platform).
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Fixnum+and+long Source
*/
class packed_int_t : public kaitai::kstruct {
public:
packed_int_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~packed_int_t();
private:
bool f_is_immediate;
bool m_is_immediate;
public:
bool is_immediate();
private:
bool f_value;
int32_t m_value;
public:
int32_t value();
private:
uint8_t m_code;
uint32_t m_encoded;
bool n_encoded;
public:
bool _is_null_encoded() { encoded(); return n_encoded; };
private:
uint8_t m_encoded2;
bool n_encoded2;
public:
bool _is_null_encoded2() { encoded2(); return n_encoded2; };
private:
ruby_marshal_t* m__root;
kaitai::kstruct* m__parent;
public:
uint8_t code() const { return m_code; }
uint32_t encoded() const { return m_encoded; }
/**
* One extra byte for 3-byte integers (0x03 and 0xfd), as
* there is no standard `u3` type in KS.
*/
uint8_t encoded2() const { return m_encoded2; }
ruby_marshal_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
class pair_t : public kaitai::kstruct {
public:
pair_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~pair_t();
private:
record_t* m_key;
record_t* m_value;
ruby_marshal_t* m__root;
kaitai::kstruct* m__parent;
public:
record_t* key() const { return m_key; }
record_t* value() const { return m_value; }
ruby_marshal_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
/**
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Instance+Variables Source
*/
class instance_var_t : public kaitai::kstruct {
public:
instance_var_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~instance_var_t();
private:
record_t* m_obj;
packed_int_t* m_num_vars;
std::vector<pair_t*>* m_vars;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
record_t* obj() const { return m_obj; }
packed_int_t* num_vars() const { return m_num_vars; }
std::vector<pair_t*>* vars() const { return m_vars; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
/**
* Each record starts with a single byte that determines its type
* (`code`) and contents. If necessary, additional info as parsed
* as `body`, to be determined by `code`.
*/
class record_t : public kaitai::kstruct {
public:
record_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~record_t();
private:
codes_t m_code;
kaitai::kstruct* m_body;
bool n_body;
public:
bool _is_null_body() { body(); return n_body; };
private:
ruby_marshal_t* m__root;
kaitai::kstruct* m__parent;
public:
codes_t code() const { return m_code; }
kaitai::kstruct* body() const { return m_body; }
ruby_marshal_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
/**
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-Hash+and+Hash+with+Default+Value Source
*/
class ruby_hash_t : public kaitai::kstruct {
public:
ruby_hash_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~ruby_hash_t();
private:
packed_int_t* m_num_pairs;
std::vector<pair_t*>* m_pairs;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
packed_int_t* num_pairs() const { return m_num_pairs; }
std::vector<pair_t*>* pairs() const { return m_pairs; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
/**
* \sa https://docs.ruby-lang.org/en/2.4.0/marshal_rdoc.html#label-String Source
*/
class ruby_string_t : public kaitai::kstruct {
public:
ruby_string_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent = 0, ruby_marshal_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~ruby_string_t();
private:
packed_int_t* m_len;
std::string m_body;
ruby_marshal_t* m__root;
ruby_marshal_t::record_t* m__parent;
public:
packed_int_t* len() const { return m_len; }
std::string body() const { return m_body; }
ruby_marshal_t* _root() const { return m__root; }
ruby_marshal_t::record_t* _parent() const { return m__parent; }
};
private:
std::string m_version;
record_t* m_records;
ruby_marshal_t* m__root;
kaitai::kstruct* m__parent;
public:
std::string version() const { return m_version; }
record_t* records() const { return m_records; }
ruby_marshal_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
#endif // RUBY_MARSHAL_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "ruby_marshal.h"
#include "kaitai/exceptions.h"
ruby_marshal_t::ruby_marshal_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_records = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::_read() {
m_version = m__io->read_bytes(2);
if (!(version() == std::string("\x04\x08", 2))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x04\x08", 2), version(), _io(), std::string("/seq/0"));
}
m_records = new record_t(m__io, this, m__root);
}
ruby_marshal_t::~ruby_marshal_t() {
_clean_up();
}
void ruby_marshal_t::_clean_up() {
if (m_records) {
delete m_records; m_records = 0;
}
}
ruby_marshal_t::ruby_array_t::ruby_array_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_num_elements = 0;
m_elements = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::ruby_array_t::_read() {
m_num_elements = new packed_int_t(m__io, this, m__root);
m_elements = new std::vector<record_t*>();
const int l_elements = num_elements()->value();
for (int i = 0; i < l_elements; i++) {
m_elements->push_back(new record_t(m__io, this, m__root));
}
}
ruby_marshal_t::ruby_array_t::~ruby_array_t() {
_clean_up();
}
void ruby_marshal_t::ruby_array_t::_clean_up() {
if (m_num_elements) {
delete m_num_elements; m_num_elements = 0;
}
if (m_elements) {
for (std::vector<record_t*>::iterator it = m_elements->begin(); it != m_elements->end(); ++it) {
delete *it;
}
delete m_elements; m_elements = 0;
}
}
ruby_marshal_t::bignum_t::bignum_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_len_div_2 = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::bignum_t::_read() {
m_sign = m__io->read_u1();
m_len_div_2 = new packed_int_t(m__io, this, m__root);
m_body = m__io->read_bytes((len_div_2()->value() * 2));
}
ruby_marshal_t::bignum_t::~bignum_t() {
_clean_up();
}
void ruby_marshal_t::bignum_t::_clean_up() {
if (m_len_div_2) {
delete m_len_div_2; m_len_div_2 = 0;
}
}
ruby_marshal_t::ruby_struct_t::ruby_struct_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_name = 0;
m_num_members = 0;
m_members = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::ruby_struct_t::_read() {
m_name = new record_t(m__io, this, m__root);
m_num_members = new packed_int_t(m__io, this, m__root);
m_members = new std::vector<pair_t*>();
const int l_members = num_members()->value();
for (int i = 0; i < l_members; i++) {
m_members->push_back(new pair_t(m__io, this, m__root));
}
}
ruby_marshal_t::ruby_struct_t::~ruby_struct_t() {
_clean_up();
}
void ruby_marshal_t::ruby_struct_t::_clean_up() {
if (m_name) {
delete m_name; m_name = 0;
}
if (m_num_members) {
delete m_num_members; m_num_members = 0;
}
if (m_members) {
for (std::vector<pair_t*>::iterator it = m_members->begin(); it != m_members->end(); ++it) {
delete *it;
}
delete m_members; m_members = 0;
}
}
ruby_marshal_t::ruby_symbol_t::ruby_symbol_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_len = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::ruby_symbol_t::_read() {
m_len = new packed_int_t(m__io, this, m__root);
m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(len()->value()), std::string("UTF-8"));
}
ruby_marshal_t::ruby_symbol_t::~ruby_symbol_t() {
_clean_up();
}
void ruby_marshal_t::ruby_symbol_t::_clean_up() {
if (m_len) {
delete m_len; m_len = 0;
}
}
ruby_marshal_t::packed_int_t::packed_int_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
f_is_immediate = false;
f_value = false;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::packed_int_t::_read() {
m_code = m__io->read_u1();
n_encoded = true;
switch (code()) {
case 4: {
n_encoded = false;
m_encoded = m__io->read_u4le();
break;
}
case 1: {
n_encoded = false;
m_encoded = m__io->read_u1();
break;
}
case 252: {
n_encoded = false;
m_encoded = m__io->read_u4le();
break;
}
case 253: {
n_encoded = false;
m_encoded = m__io->read_u2le();
break;
}
case 3: {
n_encoded = false;
m_encoded = m__io->read_u2le();
break;
}
case 2: {
n_encoded = false;
m_encoded = m__io->read_u2le();
break;
}
case 255: {
n_encoded = false;
m_encoded = m__io->read_u1();
break;
}
case 254: {
n_encoded = false;
m_encoded = m__io->read_u2le();
break;
}
}
n_encoded2 = true;
switch (code()) {
case 3: {
n_encoded2 = false;
m_encoded2 = m__io->read_u1();
break;
}
case 253: {
n_encoded2 = false;
m_encoded2 = m__io->read_u1();
break;
}
}
}
ruby_marshal_t::packed_int_t::~packed_int_t() {
_clean_up();
}
void ruby_marshal_t::packed_int_t::_clean_up() {
if (!n_encoded) {
}
if (!n_encoded2) {
}
}
bool ruby_marshal_t::packed_int_t::is_immediate() {
if (f_is_immediate)
return m_is_immediate;
m_is_immediate = ((code() > 4) && (code() < 252)) ;
f_is_immediate = true;
return m_is_immediate;
}
int32_t ruby_marshal_t::packed_int_t::value() {
if (f_value)
return m_value;
m_value = ((is_immediate()) ? (((code() < 128) ? ((code() - 5)) : ((4 - (~(code()) & 127))))) : (((code() == 0) ? (0) : (((code() == 255) ? ((encoded() - 256)) : (((code() == 254) ? ((encoded() - 65536)) : (((code() == 253) ? ((((encoded2() << 16) | encoded()) - 16777216)) : (((code() == 3) ? (((encoded2() << 16) | encoded())) : (encoded()))))))))))));
f_value = true;
return m_value;
}
ruby_marshal_t::pair_t::pair_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_key = 0;
m_value = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::pair_t::_read() {
m_key = new record_t(m__io, this, m__root);
m_value = new record_t(m__io, this, m__root);
}
ruby_marshal_t::pair_t::~pair_t() {
_clean_up();
}
void ruby_marshal_t::pair_t::_clean_up() {
if (m_key) {
delete m_key; m_key = 0;
}
if (m_value) {
delete m_value; m_value = 0;
}
}
ruby_marshal_t::instance_var_t::instance_var_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_obj = 0;
m_num_vars = 0;
m_vars = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::instance_var_t::_read() {
m_obj = new record_t(m__io, this, m__root);
m_num_vars = new packed_int_t(m__io, this, m__root);
m_vars = new std::vector<pair_t*>();
const int l_vars = num_vars()->value();
for (int i = 0; i < l_vars; i++) {
m_vars->push_back(new pair_t(m__io, this, m__root));
}
}
ruby_marshal_t::instance_var_t::~instance_var_t() {
_clean_up();
}
void ruby_marshal_t::instance_var_t::_clean_up() {
if (m_obj) {
delete m_obj; m_obj = 0;
}
if (m_num_vars) {
delete m_num_vars; m_num_vars = 0;
}
if (m_vars) {
for (std::vector<pair_t*>::iterator it = m_vars->begin(); it != m_vars->end(); ++it) {
delete *it;
}
delete m_vars; m_vars = 0;
}
}
ruby_marshal_t::record_t::record_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::record_t::_read() {
m_code = static_cast<ruby_marshal_t::codes_t>(m__io->read_u1());
n_body = true;
switch (code()) {
case ruby_marshal_t::CODES_PACKED_INT: {
n_body = false;
m_body = new packed_int_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_BIGNUM: {
n_body = false;
m_body = new bignum_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_ARRAY: {
n_body = false;
m_body = new ruby_array_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_SYMBOL_LINK: {
n_body = false;
m_body = new packed_int_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_STRUCT: {
n_body = false;
m_body = new ruby_struct_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_STRING: {
n_body = false;
m_body = new ruby_string_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_INSTANCE_VAR: {
n_body = false;
m_body = new instance_var_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_HASH: {
n_body = false;
m_body = new ruby_hash_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_SYMBOL: {
n_body = false;
m_body = new ruby_symbol_t(m__io, this, m__root);
break;
}
case ruby_marshal_t::CODES_RUBY_OBJECT_LINK: {
n_body = false;
m_body = new packed_int_t(m__io, this, m__root);
break;
}
}
}
ruby_marshal_t::record_t::~record_t() {
_clean_up();
}
void ruby_marshal_t::record_t::_clean_up() {
if (!n_body) {
if (m_body) {
delete m_body; m_body = 0;
}
}
}
ruby_marshal_t::ruby_hash_t::ruby_hash_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_num_pairs = 0;
m_pairs = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::ruby_hash_t::_read() {
m_num_pairs = new packed_int_t(m__io, this, m__root);
m_pairs = new std::vector<pair_t*>();
const int l_pairs = num_pairs()->value();
for (int i = 0; i < l_pairs; i++) {
m_pairs->push_back(new pair_t(m__io, this, m__root));
}
}
ruby_marshal_t::ruby_hash_t::~ruby_hash_t() {
_clean_up();
}
void ruby_marshal_t::ruby_hash_t::_clean_up() {
if (m_num_pairs) {
delete m_num_pairs; m_num_pairs = 0;
}
if (m_pairs) {
for (std::vector<pair_t*>::iterator it = m_pairs->begin(); it != m_pairs->end(); ++it) {
delete *it;
}
delete m_pairs; m_pairs = 0;
}
}
ruby_marshal_t::ruby_string_t::ruby_string_t(kaitai::kstream* p__io, ruby_marshal_t::record_t* p__parent, ruby_marshal_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_len = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void ruby_marshal_t::ruby_string_t::_read() {
m_len = new packed_int_t(m__io, this, m__root);
m_body = m__io->read_bytes(len()->value());
}
ruby_marshal_t::ruby_string_t::~ruby_string_t() {
_clean_up();
}
void ruby_marshal_t::ruby_string_t::_clean_up() {
if (m_len) {
delete m_len; m_len = 0;
}
}