This page hosts a formal specification of .pak file format of Dune 2 game engine 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++11/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.pak", 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);
dune_2_pak_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.dir() // => get dir
#pragma once
// 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 <memory>
#include <vector>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
/**
* \sa https://moddingwiki.shikadi.net/wiki/PAK_Format_(Westwood) Source
*/
class dune_2_pak_t : public kaitai::kstruct {
public:
class files_t;
class file_t;
dune_2_pak_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, dune_2_pak_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~dune_2_pak_t();
class files_t : public kaitai::kstruct {
public:
files_t(kaitai::kstream* p__io, dune_2_pak_t* p__parent = nullptr, dune_2_pak_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~files_t();
private:
std::unique_ptr<std::vector<std::unique_ptr<file_t>>> m_files;
dune_2_pak_t* m__root;
dune_2_pak_t* m__parent;
public:
std::vector<std::unique_ptr<file_t>>* files() const { return m_files.get(); }
dune_2_pak_t* _root() const { return m__root; }
dune_2_pak_t* _parent() const { return m__parent; }
};
class file_t : public kaitai::kstruct {
public:
file_t(uint32_t p_idx, kaitai::kstream* p__io, dune_2_pak_t::files_t* p__parent = nullptr, dune_2_pak_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~file_t();
private:
bool f_next_ofs0;
uint32_t m_next_ofs0;
bool n_next_ofs0;
public:
bool _is_null_next_ofs0() { next_ofs0(); return n_next_ofs0; };
private:
public:
uint32_t next_ofs0();
private:
bool f_next_ofs;
int32_t m_next_ofs;
bool n_next_ofs;
public:
bool _is_null_next_ofs() { next_ofs(); return n_next_ofs; };
private:
public:
int32_t next_ofs();
private:
bool f_body;
std::string m_body;
bool n_body;
public:
bool _is_null_body() { body(); return n_body; };
private:
public:
std::string body();
private:
uint32_t m_ofs;
std::string m_file_name;
bool n_file_name;
public:
bool _is_null_file_name() { file_name(); return n_file_name; };
private:
uint32_t m_idx;
dune_2_pak_t* m__root;
dune_2_pak_t::files_t* m__parent;
public:
uint32_t ofs() const { return m_ofs; }
std::string file_name() const { return m_file_name; }
uint32_t idx() const { return m_idx; }
dune_2_pak_t* _root() const { return m__root; }
dune_2_pak_t::files_t* _parent() const { return m__parent; }
};
private:
bool f_dir_size;
uint32_t m_dir_size;
public:
uint32_t dir_size();
private:
std::unique_ptr<files_t> m_dir;
dune_2_pak_t* m__root;
kaitai::kstruct* m__parent;
std::string m__raw_dir;
std::unique_ptr<kaitai::kstream> m__io__raw_dir;
public:
files_t* dir() const { return m_dir.get(); }
dune_2_pak_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
std::string _raw_dir() const { return m__raw_dir; }
kaitai::kstream* _io__raw_dir() const { return m__io__raw_dir.get(); }
};
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "dune_2_pak.h"
dune_2_pak_t::dune_2_pak_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, dune_2_pak_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_dir = nullptr;
m__io__raw_dir = nullptr;
f_dir_size = false;
_read();
}
void dune_2_pak_t::_read() {
m__raw_dir = m__io->read_bytes(dir_size());
m__io__raw_dir = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_dir));
m_dir = std::unique_ptr<files_t>(new files_t(m__io__raw_dir.get(), this, m__root));
}
dune_2_pak_t::~dune_2_pak_t() {
_clean_up();
}
void dune_2_pak_t::_clean_up() {
if (f_dir_size) {
}
}
dune_2_pak_t::files_t::files_t(kaitai::kstream* p__io, dune_2_pak_t* p__parent, dune_2_pak_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_files = nullptr;
_read();
}
void dune_2_pak_t::files_t::_read() {
m_files = std::unique_ptr<std::vector<std::unique_ptr<file_t>>>(new std::vector<std::unique_ptr<file_t>>());
{
int i = 0;
while (!m__io->is_eof()) {
m_files->push_back(std::move(std::unique_ptr<file_t>(new file_t(i, m__io, this, m__root))));
i++;
}
}
}
dune_2_pak_t::files_t::~files_t() {
_clean_up();
}
void dune_2_pak_t::files_t::_clean_up() {
}
dune_2_pak_t::file_t::file_t(uint32_t p_idx, kaitai::kstream* p__io, dune_2_pak_t::files_t* p__parent, dune_2_pak_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_idx = p_idx;
f_next_ofs0 = false;
f_next_ofs = false;
f_body = false;
_read();
}
void dune_2_pak_t::file_t::_read() {
m_ofs = m__io->read_u4le();
n_file_name = true;
if (ofs() != 0) {
n_file_name = false;
m_file_name = kaitai::kstream::bytes_to_str(m__io->read_bytes_term(0, false, true, true), std::string("ASCII"));
}
}
dune_2_pak_t::file_t::~file_t() {
_clean_up();
}
void dune_2_pak_t::file_t::_clean_up() {
if (!n_file_name) {
}
if (f_body && !n_body) {
}
}
uint32_t dune_2_pak_t::file_t::next_ofs0() {
if (f_next_ofs0)
return m_next_ofs0;
n_next_ofs0 = true;
if (ofs() != 0) {
n_next_ofs0 = false;
m_next_ofs0 = _root()->dir()->files()->at((idx() + 1))->ofs();
}
f_next_ofs0 = true;
return m_next_ofs0;
}
int32_t dune_2_pak_t::file_t::next_ofs() {
if (f_next_ofs)
return m_next_ofs;
n_next_ofs = true;
if (ofs() != 0) {
n_next_ofs = false;
m_next_ofs = ((next_ofs0() == 0) ? (_root()->_io()->size()) : (next_ofs0()));
}
f_next_ofs = true;
return m_next_ofs;
}
std::string dune_2_pak_t::file_t::body() {
if (f_body)
return m_body;
n_body = true;
if (ofs() != 0) {
n_body = false;
kaitai::kstream *io = _root()->_io();
std::streampos _pos = io->pos();
io->seek(ofs());
m_body = io->read_bytes((next_ofs() - ofs()));
io->seek(_pos);
f_body = true;
}
return m_body;
}
uint32_t dune_2_pak_t::dir_size() {
if (f_dir_size)
return m_dir_size;
std::streampos _pos = m__io->pos();
m__io->seek(0);
m_dir_size = m__io->read_u4le();
m__io->seek(_pos);
f_dir_size = true;
return m_dir_size;
}