Saints Rows 2 game packages: C++/STL parsing library

File extension

vpp_pc

KS implementation details

License: MIT

This page hosts a formal specification of Saints Rows 2 game packages using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream).
    • One can open a stream for reading from a local file:
      #include <fstream>
      
      std::ifstream is("path/to/local/file.vpp_pc", std::ifstream::binary);
    • Or one can prepare a stream for reading from existing std::string str:
      #include <sstream>
      
      std::istringstream is(str);
    • Or one can parse arbitrary char* buffer in memory, given that we know its size:
      #include <sstream>
      
      const char buf[] = { ... };
      std::string str(buf, sizeof buf);
      std::istringstream is(str);
  2. We need to wrap our input stream into Kaitai stream:
    #include <kaitai/kaitaistream.h>
    
    kaitai::kstream ks(&is);
  3. And finally, we can invoke the parsing:
    saints_row_2_vpp_pc_t data(&ks);

After that, one can get various attributes from the structure by invoking getter methods like:

data.magic() // => get magic

C++/STL source code to parse Saints Rows 2 game packages

saints_row_2_vpp_pc.h

#ifndef SAINTS_ROW_2_VPP_PC_H_
#define SAINTS_ROW_2_VPP_PC_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 < 7000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.7 or later is required"
#endif

class saints_row_2_vpp_pc_t : public kaitai::kstruct {

public:
    class offsets_t;
    class strings_t;

    saints_row_2_vpp_pc_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, saints_row_2_vpp_pc_t* p__root = 0);

private:
    void _read();

public:
    ~saints_row_2_vpp_pc_t();

    class offsets_t : public kaitai::kstruct {

    public:
        class offset_t;

        offsets_t(kaitai::kstream* p__io, saints_row_2_vpp_pc_t* p__parent = 0, saints_row_2_vpp_pc_t* p__root = 0);

    private:
        void _read();

    public:
        ~offsets_t();

        class offset_t : public kaitai::kstruct {

        public:

            offset_t(kaitai::kstream* p__io, saints_row_2_vpp_pc_t::offsets_t* p__parent = 0, saints_row_2_vpp_pc_t* p__root = 0);

        private:
            void _read();

        public:
            ~offset_t();

        private:
            bool f_filename;
            std::string m_filename;

        public:
            std::string filename();

        private:
            bool f_ext;
            std::string m_ext;

        public:
            std::string ext();

        private:
            bool f_body;
            std::string m_body;

        public:
            std::string body();

        private:
            uint32_t m_name_ofs;
            uint32_t m_ext_ofs;
            int32_t m_smth2;
            int32_t m_ofs_body;
            int32_t m_len_body;
            int32_t m_always_minus_1;
            int32_t m_always_zero;
            saints_row_2_vpp_pc_t* m__root;
            saints_row_2_vpp_pc_t::offsets_t* m__parent;

        public:
            uint32_t name_ofs() const { return m_name_ofs; }
            uint32_t ext_ofs() const { return m_ext_ofs; }
            int32_t smth2() const { return m_smth2; }
            int32_t ofs_body() const { return m_ofs_body; }
            int32_t len_body() const { return m_len_body; }
            int32_t always_minus_1() const { return m_always_minus_1; }
            int32_t always_zero() const { return m_always_zero; }
            saints_row_2_vpp_pc_t* _root() const { return m__root; }
            saints_row_2_vpp_pc_t::offsets_t* _parent() const { return m__parent; }
        };

    private:
        std::vector<offset_t*>* m_entries;
        saints_row_2_vpp_pc_t* m__root;
        saints_row_2_vpp_pc_t* m__parent;

    public:
        std::vector<offset_t*>* entries() const { return m_entries; }
        saints_row_2_vpp_pc_t* _root() const { return m__root; }
        saints_row_2_vpp_pc_t* _parent() const { return m__parent; }
    };

    class strings_t : public kaitai::kstruct {

    public:

        strings_t(kaitai::kstream* p__io, saints_row_2_vpp_pc_t* p__parent = 0, saints_row_2_vpp_pc_t* p__root = 0);

    private:
        void _read();

    public:
        ~strings_t();

    private:
        std::vector<std::string>* m_entries;
        saints_row_2_vpp_pc_t* m__root;
        saints_row_2_vpp_pc_t* m__parent;

    public:
        std::vector<std::string>* entries() const { return m_entries; }
        saints_row_2_vpp_pc_t* _root() const { return m__root; }
        saints_row_2_vpp_pc_t* _parent() const { return m__parent; }
    };

private:
    bool f_filenames;
    strings_t* m_filenames;

public:
    strings_t* filenames();

private:
    bool f_ofs_extensions;
    int32_t m_ofs_extensions;

public:
    int32_t ofs_extensions();

private:
    bool f_files;
    offsets_t* m_files;

public:
    offsets_t* files();

private:
    bool f_data_start;
    int32_t m_data_start;

public:
    int32_t data_start();

private:
    bool f_extensions;
    strings_t* m_extensions;

public:
    strings_t* extensions();

private:
    bool f_ofs_filenames;
    int32_t m_ofs_filenames;

public:
    int32_t ofs_filenames();

private:
    std::string m_magic;
    std::string m_pad1;
    int32_t m_num_files;
    int32_t m_container_size;
    int32_t m_len_offsets;
    int32_t m_len_filenames;
    int32_t m_len_extensions;
    int32_t m_smth5;
    int32_t m_smth6;
    int32_t m_smth7;
    int32_t m_smth8;
    int32_t m_smth9;
    saints_row_2_vpp_pc_t* m__root;
    kaitai::kstruct* m__parent;
    std::string m__raw_filenames;
    kaitai::kstream* m__io__raw_filenames;
    std::string m__raw_files;
    kaitai::kstream* m__io__raw_files;
    std::string m__raw_extensions;
    kaitai::kstream* m__io__raw_extensions;

public:
    std::string magic() const { return m_magic; }
    std::string pad1() const { return m_pad1; }
    int32_t num_files() const { return m_num_files; }
    int32_t container_size() const { return m_container_size; }
    int32_t len_offsets() const { return m_len_offsets; }
    int32_t len_filenames() const { return m_len_filenames; }
    int32_t len_extensions() const { return m_len_extensions; }
    int32_t smth5() const { return m_smth5; }
    int32_t smth6() const { return m_smth6; }
    int32_t smth7() const { return m_smth7; }
    int32_t smth8() const { return m_smth8; }
    int32_t smth9() const { return m_smth9; }
    saints_row_2_vpp_pc_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::string _raw_filenames() const { return m__raw_filenames; }
    kaitai::kstream* _io__raw_filenames() const { return m__io__raw_filenames; }
    std::string _raw_files() const { return m__raw_files; }
    kaitai::kstream* _io__raw_files() const { return m__io__raw_files; }
    std::string _raw_extensions() const { return m__raw_extensions; }
    kaitai::kstream* _io__raw_extensions() const { return m__io__raw_extensions; }
};

#endif  // SAINTS_ROW_2_VPP_PC_H_

saints_row_2_vpp_pc.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "saints_row_2_vpp_pc.h"



saints_row_2_vpp_pc_t::saints_row_2_vpp_pc_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, saints_row_2_vpp_pc_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    f_filenames = false;
    f_ofs_extensions = false;
    f_files = false;
    f_data_start = false;
    f_extensions = false;
    f_ofs_filenames = false;
    _read();
}

void saints_row_2_vpp_pc_t::_read() {
    m_magic = m__io->ensure_fixed_contents(std::string("\xCE\x0A\x89\x51\x04", 5));
    m_pad1 = m__io->read_bytes(335);
    m_num_files = m__io->read_s4le();
    m_container_size = m__io->read_s4le();
    m_len_offsets = m__io->read_s4le();
    m_len_filenames = m__io->read_s4le();
    m_len_extensions = m__io->read_s4le();
    m_smth5 = m__io->read_s4le();
    m_smth6 = m__io->read_s4le();
    m_smth7 = m__io->read_s4le();
    m_smth8 = m__io->read_s4le();
    m_smth9 = m__io->read_s4le();
}

saints_row_2_vpp_pc_t::~saints_row_2_vpp_pc_t() {
    if (f_filenames) {
        delete m__io__raw_filenames;
        delete m_filenames;
    }
    if (f_files) {
        delete m__io__raw_files;
        delete m_files;
    }
    if (f_extensions) {
        delete m__io__raw_extensions;
        delete m_extensions;
    }
}

saints_row_2_vpp_pc_t::offsets_t::offsets_t(kaitai::kstream* p__io, saints_row_2_vpp_pc_t* p__parent, saints_row_2_vpp_pc_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void saints_row_2_vpp_pc_t::offsets_t::_read() {
    m_entries = new std::vector<offset_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(new offset_t(m__io, this, m__root));
            i++;
        }
    }
}

saints_row_2_vpp_pc_t::offsets_t::~offsets_t() {
    for (std::vector<offset_t*>::iterator it = m_entries->begin(); it != m_entries->end(); ++it) {
        delete *it;
    }
    delete m_entries;
}

saints_row_2_vpp_pc_t::offsets_t::offset_t::offset_t(kaitai::kstream* p__io, saints_row_2_vpp_pc_t::offsets_t* p__parent, saints_row_2_vpp_pc_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_filename = false;
    f_ext = false;
    f_body = false;
    _read();
}

void saints_row_2_vpp_pc_t::offsets_t::offset_t::_read() {
    m_name_ofs = m__io->read_u4le();
    m_ext_ofs = m__io->read_u4le();
    m_smth2 = m__io->read_s4le();
    m_ofs_body = m__io->read_s4le();
    m_len_body = m__io->read_s4le();
    m_always_minus_1 = m__io->read_s4le();
    m_always_zero = m__io->read_s4le();
}

saints_row_2_vpp_pc_t::offsets_t::offset_t::~offset_t() {
    if (f_filename) {
    }
    if (f_ext) {
    }
    if (f_body) {
    }
}

std::string saints_row_2_vpp_pc_t::offsets_t::offset_t::filename() {
    if (f_filename)
        return m_filename;
    kaitai::kstream *io = _root()->filenames()->_io();
    std::streampos _pos = io->pos();
    io->seek(name_ofs());
    m_filename = kaitai::kstream::bytes_to_str(io->read_bytes_term(0, false, true, true), std::string("UTF-8"));
    io->seek(_pos);
    f_filename = true;
    return m_filename;
}

std::string saints_row_2_vpp_pc_t::offsets_t::offset_t::ext() {
    if (f_ext)
        return m_ext;
    kaitai::kstream *io = _root()->extensions()->_io();
    std::streampos _pos = io->pos();
    io->seek(ext_ofs());
    m_ext = kaitai::kstream::bytes_to_str(io->read_bytes_term(0, false, true, true), std::string("UTF-8"));
    io->seek(_pos);
    f_ext = true;
    return m_ext;
}

std::string saints_row_2_vpp_pc_t::offsets_t::offset_t::body() {
    if (f_body)
        return m_body;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek((_root()->data_start() + ofs_body()));
    m_body = io->read_bytes(len_body());
    io->seek(_pos);
    f_body = true;
    return m_body;
}

saints_row_2_vpp_pc_t::strings_t::strings_t(kaitai::kstream* p__io, saints_row_2_vpp_pc_t* p__parent, saints_row_2_vpp_pc_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void saints_row_2_vpp_pc_t::strings_t::_read() {
    m_entries = new std::vector<std::string>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(kaitai::kstream::bytes_to_str(m__io->read_bytes_term(0, false, true, true), std::string("UTF-8")));
            i++;
        }
    }
}

saints_row_2_vpp_pc_t::strings_t::~strings_t() {
    delete m_entries;
}

saints_row_2_vpp_pc_t::strings_t* saints_row_2_vpp_pc_t::filenames() {
    if (f_filenames)
        return m_filenames;
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_filenames());
    m__raw_filenames = m__io->read_bytes(len_filenames());
    m__io__raw_filenames = new kaitai::kstream(m__raw_filenames);
    m_filenames = new strings_t(m__io__raw_filenames, this, m__root);
    m__io->seek(_pos);
    f_filenames = true;
    return m_filenames;
}

int32_t saints_row_2_vpp_pc_t::ofs_extensions() {
    if (f_ofs_extensions)
        return m_ofs_extensions;
    m_ofs_extensions = (((ofs_filenames() + len_filenames()) & 4294965248) + 2048);
    f_ofs_extensions = true;
    return m_ofs_extensions;
}

saints_row_2_vpp_pc_t::offsets_t* saints_row_2_vpp_pc_t::files() {
    if (f_files)
        return m_files;
    std::streampos _pos = m__io->pos();
    m__io->seek(2048);
    m__raw_files = m__io->read_bytes(len_offsets());
    m__io__raw_files = new kaitai::kstream(m__raw_files);
    m_files = new offsets_t(m__io__raw_files, this, m__root);
    m__io->seek(_pos);
    f_files = true;
    return m_files;
}

int32_t saints_row_2_vpp_pc_t::data_start() {
    if (f_data_start)
        return m_data_start;
    m_data_start = (((ofs_extensions() + len_extensions()) & 4294965248) + 2048);
    f_data_start = true;
    return m_data_start;
}

saints_row_2_vpp_pc_t::strings_t* saints_row_2_vpp_pc_t::extensions() {
    if (f_extensions)
        return m_extensions;
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_extensions());
    m__raw_extensions = m__io->read_bytes(len_extensions());
    m__io__raw_extensions = new kaitai::kstream(m__raw_extensions);
    m_extensions = new strings_t(m__io__raw_extensions, this, m__root);
    m__io->seek(_pos);
    f_extensions = true;
    return m_extensions;
}

int32_t saints_row_2_vpp_pc_t::ofs_filenames() {
    if (f_ofs_filenames)
        return m_ofs_filenames;
    m_ofs_filenames = (((2048 + len_offsets()) & 4294965248) + 2048);
    f_ofs_filenames = true;
    return m_ofs_filenames;
}