This page hosts a formal specification of VMWare Virtual Disk 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.vmdk", 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);
vmware_vmdk_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.size_max() // => Maximum number of sectors in a given image file (capacity)
#ifndef VMWARE_VMDK_H_
#define VMWARE_VMDK_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>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
/**
* \sa https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc#41-file-header Source
*/
class vmware_vmdk_t : public kaitai::kstruct {
public:
class header_flags_t;
enum compression_methods_t {
COMPRESSION_METHODS_NONE = 0,
COMPRESSION_METHODS_DEFLATE = 1
};
vmware_vmdk_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, vmware_vmdk_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~vmware_vmdk_t();
/**
* \sa https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc#411-flags Source
*/
class header_flags_t : public kaitai::kstruct {
public:
header_flags_t(kaitai::kstream* p__io, vmware_vmdk_t* p__parent = 0, vmware_vmdk_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~header_flags_t();
private:
uint64_t m_reserved1;
bool m_zeroed_grain_table_entry;
bool m_use_secondary_grain_dir;
bool m_valid_new_line_detection_test;
uint8_t m_reserved2;
uint64_t m_reserved3;
bool m_has_metadata;
bool m_has_compressed_grain;
uint8_t m_reserved4;
vmware_vmdk_t* m__root;
vmware_vmdk_t* m__parent;
public:
uint64_t reserved1() const { return m_reserved1; }
bool zeroed_grain_table_entry() const { return m_zeroed_grain_table_entry; }
bool use_secondary_grain_dir() const { return m_use_secondary_grain_dir; }
bool valid_new_line_detection_test() const { return m_valid_new_line_detection_test; }
uint8_t reserved2() const { return m_reserved2; }
uint64_t reserved3() const { return m_reserved3; }
bool has_metadata() const { return m_has_metadata; }
bool has_compressed_grain() const { return m_has_compressed_grain; }
uint8_t reserved4() const { return m_reserved4; }
vmware_vmdk_t* _root() const { return m__root; }
vmware_vmdk_t* _parent() const { return m__parent; }
};
private:
bool f_len_sector;
int32_t m_len_sector;
public:
int32_t len_sector();
private:
bool f_descriptor;
std::string m_descriptor;
public:
std::string descriptor();
private:
bool f_grain_primary;
std::string m_grain_primary;
public:
std::string grain_primary();
private:
bool f_grain_secondary;
std::string m_grain_secondary;
public:
std::string grain_secondary();
private:
std::string m_magic;
int32_t m_version;
header_flags_t* m_flags;
int64_t m_size_max;
int64_t m_size_grain;
int64_t m_start_descriptor;
int64_t m_size_descriptor;
int32_t m_num_grain_table_entries;
int64_t m_start_secondary_grain;
int64_t m_start_primary_grain;
int64_t m_size_metadata;
uint8_t m_is_dirty;
std::string m_stuff;
compression_methods_t m_compression_method;
vmware_vmdk_t* m__root;
kaitai::kstruct* m__parent;
public:
std::string magic() const { return m_magic; }
int32_t version() const { return m_version; }
header_flags_t* flags() const { return m_flags; }
/**
* Maximum number of sectors in a given image file (capacity)
*/
int64_t size_max() const { return m_size_max; }
int64_t size_grain() const { return m_size_grain; }
/**
* Embedded descriptor file start sector number (0 if not available)
*/
int64_t start_descriptor() const { return m_start_descriptor; }
/**
* Number of sectors that embedded descriptor file occupies
*/
int64_t size_descriptor() const { return m_size_descriptor; }
/**
* Number of grains table entries
*/
int32_t num_grain_table_entries() const { return m_num_grain_table_entries; }
/**
* Secondary (backup) grain directory start sector number
*/
int64_t start_secondary_grain() const { return m_start_secondary_grain; }
/**
* Primary grain directory start sector number
*/
int64_t start_primary_grain() const { return m_start_primary_grain; }
int64_t size_metadata() const { return m_size_metadata; }
uint8_t is_dirty() const { return m_is_dirty; }
std::string stuff() const { return m_stuff; }
compression_methods_t compression_method() const { return m_compression_method; }
vmware_vmdk_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
#endif // VMWARE_VMDK_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "vmware_vmdk.h"
#include "kaitai/exceptions.h"
vmware_vmdk_t::vmware_vmdk_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, vmware_vmdk_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_flags = 0;
f_len_sector = false;
f_descriptor = false;
f_grain_primary = false;
f_grain_secondary = false;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void vmware_vmdk_t::_read() {
m_magic = m__io->read_bytes(4);
if (!(magic() == std::string("\x4B\x44\x4D\x56", 4))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x4B\x44\x4D\x56", 4), magic(), _io(), std::string("/seq/0"));
}
m_version = m__io->read_s4le();
m_flags = new header_flags_t(m__io, this, m__root);
m_size_max = m__io->read_s8le();
m_size_grain = m__io->read_s8le();
m_start_descriptor = m__io->read_s8le();
m_size_descriptor = m__io->read_s8le();
m_num_grain_table_entries = m__io->read_s4le();
m_start_secondary_grain = m__io->read_s8le();
m_start_primary_grain = m__io->read_s8le();
m_size_metadata = m__io->read_s8le();
m_is_dirty = m__io->read_u1();
m_stuff = m__io->read_bytes(4);
m_compression_method = static_cast<vmware_vmdk_t::compression_methods_t>(m__io->read_u2le());
}
vmware_vmdk_t::~vmware_vmdk_t() {
_clean_up();
}
void vmware_vmdk_t::_clean_up() {
if (m_flags) {
delete m_flags; m_flags = 0;
}
if (f_descriptor) {
}
if (f_grain_primary) {
}
if (f_grain_secondary) {
}
}
vmware_vmdk_t::header_flags_t::header_flags_t(kaitai::kstream* p__io, vmware_vmdk_t* p__parent, vmware_vmdk_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void vmware_vmdk_t::header_flags_t::_read() {
m_reserved1 = m__io->read_bits_int_be(5);
m_zeroed_grain_table_entry = m__io->read_bits_int_be(1);
m_use_secondary_grain_dir = m__io->read_bits_int_be(1);
m_valid_new_line_detection_test = m__io->read_bits_int_be(1);
m__io->align_to_byte();
m_reserved2 = m__io->read_u1();
m_reserved3 = m__io->read_bits_int_be(6);
m_has_metadata = m__io->read_bits_int_be(1);
m_has_compressed_grain = m__io->read_bits_int_be(1);
m__io->align_to_byte();
m_reserved4 = m__io->read_u1();
}
vmware_vmdk_t::header_flags_t::~header_flags_t() {
_clean_up();
}
void vmware_vmdk_t::header_flags_t::_clean_up() {
}
int32_t vmware_vmdk_t::len_sector() {
if (f_len_sector)
return m_len_sector;
m_len_sector = 512;
f_len_sector = true;
return m_len_sector;
}
std::string vmware_vmdk_t::descriptor() {
if (f_descriptor)
return m_descriptor;
std::streampos _pos = m__io->pos();
m__io->seek((start_descriptor() * _root()->len_sector()));
m_descriptor = m__io->read_bytes((size_descriptor() * _root()->len_sector()));
m__io->seek(_pos);
f_descriptor = true;
return m_descriptor;
}
std::string vmware_vmdk_t::grain_primary() {
if (f_grain_primary)
return m_grain_primary;
std::streampos _pos = m__io->pos();
m__io->seek((start_primary_grain() * _root()->len_sector()));
m_grain_primary = m__io->read_bytes((size_grain() * _root()->len_sector()));
m__io->seek(_pos);
f_grain_primary = true;
return m_grain_primary;
}
std::string vmware_vmdk_t::grain_secondary() {
if (f_grain_secondary)
return m_grain_secondary;
std::streampos _pos = m__io->pos();
m__io->seek((start_secondary_grain() * _root()->len_sector()));
m_grain_secondary = m__io->read_bytes((size_grain() * _root()->len_sector()));
m__io->seek(_pos);
f_grain_secondary = true;
return m_grain_secondary;
}