Mozilla ARchive: C++11/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

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

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++11/STL source code to parse Mozilla ARchive

mozilla_mar.h

#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

/**
 * 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 = nullptr, mozilla_mar_t* p__root = nullptr);

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 = nullptr, mozilla_mar_t* p__root = nullptr);

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

    public:
        ~mar_index_t();

    private:
        uint32_t m_len_index;
        std::unique_ptr<index_entries_t> m_index_entries;
        mozilla_mar_t* m__root;
        mozilla_mar_t* m__parent;
        std::string m__raw_index_entries;
        std::unique_ptr<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.get(); }
        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.get(); }
    };

    class index_entries_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~index_entries_t();

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

    public:
        std::vector<std::unique_ptr<index_entry_t>>* index_entry() const { return m_index_entry.get(); }
        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 = nullptr, mozilla_mar_t* p__root = nullptr);

    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 = nullptr, mozilla_mar_t* p__root = nullptr);

    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 = nullptr, mozilla_mar_t* p__root = nullptr);

    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 = nullptr, mozilla_mar_t* p__root = nullptr);

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

    public:
        ~additional_section_t();

    private:
        uint32_t m_len_block;
        block_identifiers_t m_block_identifier;
        std::unique_ptr<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;
        std::unique_ptr<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.get(); }
        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.get(); }
    };

private:
    bool f_index;
    std::unique_ptr<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::unique_ptr<std::vector<std::unique_ptr<signature_t>>> m_signatures;
    uint32_t m_len_additional_sections;
    std::unique_ptr<std::vector<std::unique_ptr<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<std::unique_ptr<signature_t>>* signatures() const { return m_signatures.get(); }
    uint32_t len_additional_sections() const { return m_len_additional_sections; }
    std::vector<std::unique_ptr<additional_section_t>>* additional_sections() const { return m_additional_sections.get(); }
    mozilla_mar_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

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 = nullptr;
    m_additional_sections = nullptr;
    m_index = nullptr;
    f_index = false;
    _read();
}

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();
    int l_signatures = len_signatures();
    m_signatures = std::unique_ptr<std::vector<std::unique_ptr<signature_t>>>(new std::vector<std::unique_ptr<signature_t>>());
    m_signatures->reserve(l_signatures);
    for (int i = 0; i < l_signatures; i++) {
        m_signatures->push_back(std::move(std::unique_ptr<signature_t>(new signature_t(m__io, this, m__root))));
    }
    m_len_additional_sections = m__io->read_u4be();
    int l_additional_sections = len_additional_sections();
    m_additional_sections = std::unique_ptr<std::vector<std::unique_ptr<additional_section_t>>>(new std::vector<std::unique_ptr<additional_section_t>>());
    m_additional_sections->reserve(l_additional_sections);
    for (int i = 0; i < l_additional_sections; i++) {
        m_additional_sections->push_back(std::move(std::unique_ptr<additional_section_t>(new additional_section_t(m__io, this, m__root))));
    }
}

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

void mozilla_mar_t::_clean_up() {
    if (f_index) {
    }
}

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 = nullptr;
    m__io__raw_index_entries = nullptr;
    _read();
}

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 = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_index_entries));
    m_index_entries = std::unique_ptr<index_entries_t>(new index_entries_t(m__io__raw_index_entries.get(), this, m__root));
}

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

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

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 = nullptr;
    _read();
}

void mozilla_mar_t::index_entries_t::_read() {
    m_index_entry = std::unique_ptr<std::vector<std::unique_ptr<index_entry_t>>>(new std::vector<std::unique_ptr<index_entry_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_index_entry->push_back(std::move(std::unique_ptr<index_entry_t>(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() {
}

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;
    _read();
}

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;
    _read();
}

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;
    _read();
}

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 = nullptr;
    _read();
}

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 = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_bytes));
        m_bytes = std::unique_ptr<product_information_block_t>(new product_information_block_t(m__io__raw_bytes.get(), 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) {
    }
}

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