Mozilla ARchive: C++98/STL parsing library

Mozilla ARchive file is Mozilla's own archive format to distribute software updates. Test files can be found on Mozilla's FTP site, for example:

http://ftp.mozilla.org/pub/firefox/nightly/partials/

File extension

mar

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of Mozilla ARchive using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime 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.

Code

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 local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.mar", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #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:
    mozilla_mar_t data(&ks);
    

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

data.magic() // => get magic

C++98/STL source code to parse Mozilla ARchive

mozilla_mar.h

#ifndef MOZILLA_MAR_H_
#define MOZILLA_MAR_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

/**
 * Mozilla ARchive file is Mozilla's own archive format to distribute software updates.
 * Test files can be found on Mozilla's FTP site, for example:
 * 
 * <http://ftp.mozilla.org/pub/firefox/nightly/partials/>
 * \sa https://wiki.mozilla.org/Software_Update:MAR Source
 */

class mozilla_mar_t : public kaitai::kstruct {

public:
    class mar_index_t;
    class index_entries_t;
    class signature_t;
    class product_information_block_t;
    class index_entry_t;
    class additional_section_t;

    enum signature_algorithms_t {
        SIGNATURE_ALGORITHMS_RSA_PKCS1_SHA1 = 1,
        SIGNATURE_ALGORITHMS_RSA_PKCS1_SHA384 = 2
    };

    enum block_identifiers_t {
        BLOCK_IDENTIFIERS_PRODUCT_INFORMATION = 1
    };

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

private:
    void _read();
    void _clean_up();

public:
    ~mozilla_mar_t();

    class mar_index_t : public kaitai::kstruct {

    public:

        mar_index_t(kaitai::kstream* p__io, mozilla_mar_t* p__parent = 0, mozilla_mar_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~mar_index_t();

    private:
        uint32_t m_len_index;
        index_entries_t* m_index_entries;
        mozilla_mar_t* m__root;
        mozilla_mar_t* m__parent;
        std::string m__raw_index_entries;
        kaitai::kstream* m__io__raw_index_entries;

    public:
        uint32_t len_index() const { return m_len_index; }
        index_entries_t* index_entries() const { return m_index_entries; }
        mozilla_mar_t* _root() const { return m__root; }
        mozilla_mar_t* _parent() const { return m__parent; }
        std::string _raw_index_entries() const { return m__raw_index_entries; }
        kaitai::kstream* _io__raw_index_entries() const { return m__io__raw_index_entries; }
    };

    class index_entries_t : public kaitai::kstruct {

    public:

        index_entries_t(kaitai::kstream* p__io, mozilla_mar_t::mar_index_t* p__parent = 0, mozilla_mar_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~index_entries_t();

    private:
        std::vector<index_entry_t*>* m_index_entry;
        mozilla_mar_t* m__root;
        mozilla_mar_t::mar_index_t* m__parent;

    public:
        std::vector<index_entry_t*>* index_entry() const { return m_index_entry; }
        mozilla_mar_t* _root() const { return m__root; }
        mozilla_mar_t::mar_index_t* _parent() const { return m__parent; }
    };

    class signature_t : public kaitai::kstruct {

    public:

        signature_t(kaitai::kstream* p__io, mozilla_mar_t* p__parent = 0, mozilla_mar_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~signature_t();

    private:
        signature_algorithms_t m_algorithm;
        uint32_t m_len_signature;
        std::string m_signature;
        mozilla_mar_t* m__root;
        mozilla_mar_t* m__parent;

    public:
        signature_algorithms_t algorithm() const { return m_algorithm; }
        uint32_t len_signature() const { return m_len_signature; }
        std::string signature() const { return m_signature; }
        mozilla_mar_t* _root() const { return m__root; }
        mozilla_mar_t* _parent() const { return m__parent; }
    };

    class product_information_block_t : public kaitai::kstruct {

    public:

        product_information_block_t(kaitai::kstream* p__io, mozilla_mar_t::additional_section_t* p__parent = 0, mozilla_mar_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~product_information_block_t();

    private:
        std::string m_mar_channel_name;
        std::string m_product_version;
        mozilla_mar_t* m__root;
        mozilla_mar_t::additional_section_t* m__parent;

    public:
        std::string mar_channel_name() const { return m_mar_channel_name; }
        std::string product_version() const { return m_product_version; }
        mozilla_mar_t* _root() const { return m__root; }
        mozilla_mar_t::additional_section_t* _parent() const { return m__parent; }
    };

    class index_entry_t : public kaitai::kstruct {

    public:

        index_entry_t(kaitai::kstream* p__io, mozilla_mar_t::index_entries_t* p__parent = 0, mozilla_mar_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~index_entry_t();

    private:
        bool f_body;
        std::string m_body;

    public:
        std::string body();

    private:
        uint32_t m_ofs_content;
        uint32_t m_len_content;
        uint32_t m_flags;
        std::string m_file_name;
        mozilla_mar_t* m__root;
        mozilla_mar_t::index_entries_t* m__parent;

    public:
        uint32_t ofs_content() const { return m_ofs_content; }
        uint32_t len_content() const { return m_len_content; }

        /**
         * File permission bits (in standard unix-style format).
         */
        uint32_t flags() const { return m_flags; }
        std::string file_name() const { return m_file_name; }
        mozilla_mar_t* _root() const { return m__root; }
        mozilla_mar_t::index_entries_t* _parent() const { return m__parent; }
    };

    class additional_section_t : public kaitai::kstruct {

    public:

        additional_section_t(kaitai::kstream* p__io, mozilla_mar_t* p__parent = 0, mozilla_mar_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~additional_section_t();

    private:
        uint32_t m_len_block;
        block_identifiers_t m_block_identifier;
        product_information_block_t* m_bytes;
        bool n_bytes;

    public:
        bool _is_null_bytes() { bytes(); return n_bytes; };

    private:
        mozilla_mar_t* m__root;
        mozilla_mar_t* m__parent;
        std::string m__raw_bytes;
        kaitai::kstream* m__io__raw_bytes;

    public:
        uint32_t len_block() const { return m_len_block; }
        block_identifiers_t block_identifier() const { return m_block_identifier; }
        product_information_block_t* bytes() const { return m_bytes; }
        mozilla_mar_t* _root() const { return m__root; }
        mozilla_mar_t* _parent() const { return m__parent; }
        std::string _raw_bytes() const { return m__raw_bytes; }
        kaitai::kstream* _io__raw_bytes() const { return m__io__raw_bytes; }
    };

private:
    bool f_index;
    mar_index_t* m_index;

public:
    mar_index_t* index();

private:
    std::string m_magic;
    uint32_t m_ofs_index;
    uint64_t m_file_size;
    uint32_t m_len_signatures;
    std::vector<signature_t*>* m_signatures;
    uint32_t m_len_additional_sections;
    std::vector<additional_section_t*>* m_additional_sections;
    mozilla_mar_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::string magic() const { return m_magic; }
    uint32_t ofs_index() const { return m_ofs_index; }
    uint64_t file_size() const { return m_file_size; }
    uint32_t len_signatures() const { return m_len_signatures; }
    std::vector<signature_t*>* signatures() const { return m_signatures; }
    uint32_t len_additional_sections() const { return m_len_additional_sections; }
    std::vector<additional_section_t*>* additional_sections() const { return m_additional_sections; }
    mozilla_mar_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // MOZILLA_MAR_H_

mozilla_mar.cpp

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

#include "mozilla_mar.h"
#include "kaitai/exceptions.h"

mozilla_mar_t::mozilla_mar_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_signatures = 0;
    m_additional_sections = 0;
    m_index = 0;
    f_index = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x4D\x41\x52\x31", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x4D\x41\x52\x31", 4), magic(), _io(), std::string("/seq/0"));
    }
    m_ofs_index = m__io->read_u4be();
    m_file_size = m__io->read_u8be();
    m_len_signatures = m__io->read_u4be();
    m_signatures = new std::vector<signature_t*>();
    const int l_signatures = len_signatures();
    for (int i = 0; i < l_signatures; i++) {
        m_signatures->push_back(new signature_t(m__io, this, m__root));
    }
    m_len_additional_sections = m__io->read_u4be();
    m_additional_sections = new std::vector<additional_section_t*>();
    const int l_additional_sections = len_additional_sections();
    for (int i = 0; i < l_additional_sections; i++) {
        m_additional_sections->push_back(new additional_section_t(m__io, this, m__root));
    }
}

mozilla_mar_t::~mozilla_mar_t() {
    _clean_up();
}

void mozilla_mar_t::_clean_up() {
    if (m_signatures) {
        for (std::vector<signature_t*>::iterator it = m_signatures->begin(); it != m_signatures->end(); ++it) {
            delete *it;
        }
        delete m_signatures; m_signatures = 0;
    }
    if (m_additional_sections) {
        for (std::vector<additional_section_t*>::iterator it = m_additional_sections->begin(); it != m_additional_sections->end(); ++it) {
            delete *it;
        }
        delete m_additional_sections; m_additional_sections = 0;
    }
    if (f_index) {
        if (m_index) {
            delete m_index; m_index = 0;
        }
    }
}

mozilla_mar_t::mar_index_t::mar_index_t(kaitai::kstream* p__io, mozilla_mar_t* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_index_entries = 0;
    m__io__raw_index_entries = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::mar_index_t::_read() {
    m_len_index = m__io->read_u4be();
    m__raw_index_entries = m__io->read_bytes(len_index());
    m__io__raw_index_entries = new kaitai::kstream(m__raw_index_entries);
    m_index_entries = new index_entries_t(m__io__raw_index_entries, this, m__root);
}

mozilla_mar_t::mar_index_t::~mar_index_t() {
    _clean_up();
}

void mozilla_mar_t::mar_index_t::_clean_up() {
    if (m__io__raw_index_entries) {
        delete m__io__raw_index_entries; m__io__raw_index_entries = 0;
    }
    if (m_index_entries) {
        delete m_index_entries; m_index_entries = 0;
    }
}

mozilla_mar_t::index_entries_t::index_entries_t(kaitai::kstream* p__io, mozilla_mar_t::mar_index_t* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_index_entry = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::index_entries_t::_read() {
    m_index_entry = new std::vector<index_entry_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_index_entry->push_back(new index_entry_t(m__io, this, m__root));
            i++;
        }
    }
}

mozilla_mar_t::index_entries_t::~index_entries_t() {
    _clean_up();
}

void mozilla_mar_t::index_entries_t::_clean_up() {
    if (m_index_entry) {
        for (std::vector<index_entry_t*>::iterator it = m_index_entry->begin(); it != m_index_entry->end(); ++it) {
            delete *it;
        }
        delete m_index_entry; m_index_entry = 0;
    }
}

mozilla_mar_t::signature_t::signature_t(kaitai::kstream* p__io, mozilla_mar_t* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::signature_t::_read() {
    m_algorithm = static_cast<mozilla_mar_t::signature_algorithms_t>(m__io->read_u4be());
    m_len_signature = m__io->read_u4be();
    m_signature = m__io->read_bytes(len_signature());
}

mozilla_mar_t::signature_t::~signature_t() {
    _clean_up();
}

void mozilla_mar_t::signature_t::_clean_up() {
}

mozilla_mar_t::product_information_block_t::product_information_block_t(kaitai::kstream* p__io, mozilla_mar_t::additional_section_t* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::product_information_block_t::_read() {
    m_mar_channel_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(m__io->read_bytes(64), 0, false), std::string("UTF-8"));
    m_product_version = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(m__io->read_bytes(32), 0, false), std::string("UTF-8"));
}

mozilla_mar_t::product_information_block_t::~product_information_block_t() {
    _clean_up();
}

void mozilla_mar_t::product_information_block_t::_clean_up() {
}

mozilla_mar_t::index_entry_t::index_entry_t(kaitai::kstream* p__io, mozilla_mar_t::index_entries_t* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_body = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::index_entry_t::_read() {
    m_ofs_content = m__io->read_u4be();
    m_len_content = m__io->read_u4be();
    m_flags = m__io->read_u4be();
    m_file_name = kaitai::kstream::bytes_to_str(m__io->read_bytes_term(0, false, true, true), std::string("UTF-8"));
}

mozilla_mar_t::index_entry_t::~index_entry_t() {
    _clean_up();
}

void mozilla_mar_t::index_entry_t::_clean_up() {
    if (f_body) {
    }
}

std::string mozilla_mar_t::index_entry_t::body() {
    if (f_body)
        return m_body;
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(ofs_content());
    m_body = io->read_bytes(len_content());
    io->seek(_pos);
    f_body = true;
    return m_body;
}

mozilla_mar_t::additional_section_t::additional_section_t(kaitai::kstream* p__io, mozilla_mar_t* p__parent, mozilla_mar_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_bytes = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void mozilla_mar_t::additional_section_t::_read() {
    m_len_block = m__io->read_u4be();
    m_block_identifier = static_cast<mozilla_mar_t::block_identifiers_t>(m__io->read_u4be());
    n_bytes = true;
    switch (block_identifier()) {
    case mozilla_mar_t::BLOCK_IDENTIFIERS_PRODUCT_INFORMATION: {
        n_bytes = false;
        m__raw_bytes = m__io->read_bytes(((len_block() - 4) - 4));
        m__io__raw_bytes = new kaitai::kstream(m__raw_bytes);
        m_bytes = new product_information_block_t(m__io__raw_bytes, this, m__root);
        break;
    }
    default: {
        m__raw_bytes = m__io->read_bytes(((len_block() - 4) - 4));
        break;
    }
    }
}

mozilla_mar_t::additional_section_t::~additional_section_t() {
    _clean_up();
}

void mozilla_mar_t::additional_section_t::_clean_up() {
    if (!n_bytes) {
        if (m__io__raw_bytes) {
            delete m__io__raw_bytes; m__io__raw_bytes = 0;
        }
        if (m_bytes) {
            delete m_bytes; m_bytes = 0;
        }
    }
}

mozilla_mar_t::mar_index_t* mozilla_mar_t::index() {
    if (f_index)
        return m_index;
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_index());
    m_index = new mar_index_t(m__io, this, m__root);
    m__io->seek(_pos);
    f_index = true;
    return m_index;
}