glTF is a format for distribution of 3D models optimized for being used in software
This page hosts a formal specification of GL Transmission Format, binary container 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.glb", 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);
gltf_binary_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.header() // => get header
#ifndef GLTF_BINARY_H_
#define GLTF_BINARY_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
/**
* glTF is a format for distribution of 3D models optimized for being used in software
* \sa https://github.com/KhronosGroup/glTF/tree/2354846/specification/2.0#binary-gltf-layout Source
*/
class gltf_binary_t : public kaitai::kstruct {
public:
class header_t;
class chunk_t;
class json_t;
class bin_t;
enum chunk_type_t {
CHUNK_TYPE_BIN = 5130562,
CHUNK_TYPE_JSON = 1313821514
};
gltf_binary_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, gltf_binary_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~gltf_binary_t();
class header_t : public kaitai::kstruct {
public:
header_t(kaitai::kstream* p__io, gltf_binary_t* p__parent = 0, gltf_binary_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~header_t();
private:
std::string m_magic;
uint32_t m_version;
uint32_t m_length;
gltf_binary_t* m__root;
gltf_binary_t* m__parent;
public:
std::string magic() const { return m_magic; }
/**
* Indicates the version of the Binary glTF container format.
* For this specification, should be set to 2.
*/
uint32_t version() const { return m_version; }
/**
* Total length of the Binary glTF, including Header and all Chunks, in bytes.
*/
uint32_t length() const { return m_length; }
gltf_binary_t* _root() const { return m__root; }
gltf_binary_t* _parent() const { return m__parent; }
};
class chunk_t : public kaitai::kstruct {
public:
chunk_t(kaitai::kstream* p__io, gltf_binary_t* p__parent = 0, gltf_binary_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~chunk_t();
private:
uint32_t m_len_data;
chunk_type_t m_type;
kaitai::kstruct* m_data;
bool n_data;
public:
bool _is_null_data() { data(); return n_data; };
private:
gltf_binary_t* m__root;
gltf_binary_t* m__parent;
std::string m__raw_data;
kaitai::kstream* m__io__raw_data;
public:
uint32_t len_data() const { return m_len_data; }
chunk_type_t type() const { return m_type; }
kaitai::kstruct* data() const { return m_data; }
gltf_binary_t* _root() const { return m__root; }
gltf_binary_t* _parent() const { return m__parent; }
std::string _raw_data() const { return m__raw_data; }
kaitai::kstream* _io__raw_data() const { return m__io__raw_data; }
};
class json_t : public kaitai::kstruct {
public:
json_t(kaitai::kstream* p__io, gltf_binary_t::chunk_t* p__parent = 0, gltf_binary_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~json_t();
private:
std::string m_data;
gltf_binary_t* m__root;
gltf_binary_t::chunk_t* m__parent;
public:
/**
* This is where GLB deviates from being an elegant format.
* To parse the rest of the file, you have to parse the JSON first.
*/
std::string data() const { return m_data; }
gltf_binary_t* _root() const { return m__root; }
gltf_binary_t::chunk_t* _parent() const { return m__parent; }
};
class bin_t : public kaitai::kstruct {
public:
bin_t(kaitai::kstream* p__io, gltf_binary_t::chunk_t* p__parent = 0, gltf_binary_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~bin_t();
private:
std::string m_data;
gltf_binary_t* m__root;
gltf_binary_t::chunk_t* m__parent;
public:
std::string data() const { return m_data; }
gltf_binary_t* _root() const { return m__root; }
gltf_binary_t::chunk_t* _parent() const { return m__parent; }
};
private:
header_t* m_header;
std::vector<chunk_t*>* m_chunks;
gltf_binary_t* m__root;
kaitai::kstruct* m__parent;
public:
header_t* header() const { return m_header; }
std::vector<chunk_t*>* chunks() const { return m_chunks; }
gltf_binary_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
#endif // GLTF_BINARY_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "gltf_binary.h"
#include "kaitai/exceptions.h"
gltf_binary_t::gltf_binary_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gltf_binary_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_header = 0;
m_chunks = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void gltf_binary_t::_read() {
m_header = new header_t(m__io, this, m__root);
m_chunks = new std::vector<chunk_t*>();
{
int i = 0;
while (!m__io->is_eof()) {
m_chunks->push_back(new chunk_t(m__io, this, m__root));
i++;
}
}
}
gltf_binary_t::~gltf_binary_t() {
_clean_up();
}
void gltf_binary_t::_clean_up() {
if (m_header) {
delete m_header; m_header = 0;
}
if (m_chunks) {
for (std::vector<chunk_t*>::iterator it = m_chunks->begin(); it != m_chunks->end(); ++it) {
delete *it;
}
delete m_chunks; m_chunks = 0;
}
}
gltf_binary_t::header_t::header_t(kaitai::kstream* p__io, gltf_binary_t* p__parent, gltf_binary_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void gltf_binary_t::header_t::_read() {
m_magic = m__io->read_bytes(4);
if (!(magic() == std::string("\x67\x6C\x54\x46", 4))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x67\x6C\x54\x46", 4), magic(), _io(), std::string("/types/header/seq/0"));
}
m_version = m__io->read_u4le();
m_length = m__io->read_u4le();
}
gltf_binary_t::header_t::~header_t() {
_clean_up();
}
void gltf_binary_t::header_t::_clean_up() {
}
gltf_binary_t::chunk_t::chunk_t(kaitai::kstream* p__io, gltf_binary_t* p__parent, gltf_binary_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m__io__raw_data = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void gltf_binary_t::chunk_t::_read() {
m_len_data = m__io->read_u4le();
m_type = static_cast<gltf_binary_t::chunk_type_t>(m__io->read_u4le());
n_data = true;
switch (type()) {
case gltf_binary_t::CHUNK_TYPE_JSON: {
n_data = false;
m__raw_data = m__io->read_bytes(len_data());
m__io__raw_data = new kaitai::kstream(m__raw_data);
m_data = new json_t(m__io__raw_data, this, m__root);
break;
}
case gltf_binary_t::CHUNK_TYPE_BIN: {
n_data = false;
m__raw_data = m__io->read_bytes(len_data());
m__io__raw_data = new kaitai::kstream(m__raw_data);
m_data = new bin_t(m__io__raw_data, this, m__root);
break;
}
default: {
m__raw_data = m__io->read_bytes(len_data());
break;
}
}
}
gltf_binary_t::chunk_t::~chunk_t() {
_clean_up();
}
void gltf_binary_t::chunk_t::_clean_up() {
if (!n_data) {
if (m__io__raw_data) {
delete m__io__raw_data; m__io__raw_data = 0;
}
if (m_data) {
delete m_data; m_data = 0;
}
}
}
gltf_binary_t::json_t::json_t(kaitai::kstream* p__io, gltf_binary_t::chunk_t* p__parent, gltf_binary_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void gltf_binary_t::json_t::_read() {
m_data = kaitai::kstream::bytes_to_str(m__io->read_bytes_full(), std::string("UTF-8"));
}
gltf_binary_t::json_t::~json_t() {
_clean_up();
}
void gltf_binary_t::json_t::_clean_up() {
}
gltf_binary_t::bin_t::bin_t(kaitai::kstream* p__io, gltf_binary_t::chunk_t* p__parent, gltf_binary_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void gltf_binary_t::bin_t::_read() {
m_data = m__io->read_bytes_full();
}
gltf_binary_t::bin_t::~bin_t() {
_clean_up();
}
void gltf_binary_t::bin_t::_clean_up() {
}