.pcx file format: C++/STL parsing library

This page hosts a formal specification of .pcx file format 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.pcx", 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:
    pcx_t data(&ks);

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

data.hdr() // => get hdr

C++/STL source code to parse .pcx file format

pcx.h

#ifndef PCX_H_
#define PCX_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 pcx_t : public kaitai::kstruct {

public:
    class header_t;
    class t_palette_256_t;
    class rgb_t;

    enum versions_t {
        VERSIONS_V2_5 = 0,
        VERSIONS_V2_8_WITH_PALETTE = 2,
        VERSIONS_V2_8_WITHOUT_PALETTE = 3,
        VERSIONS_PAINTBRUSH_FOR_WINDOWS = 4,
        VERSIONS_V3_0 = 5
    };

    enum encodings_t {
        ENCODINGS_RLE = 1
    };

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

private:
    void _read();

public:
    ~pcx_t();

    /**
     * \sa - "ZSoft .PCX FILE HEADER FORMAT"
     */

    class header_t : public kaitai::kstruct {

    public:

        header_t(kaitai::kstream* p__io, pcx_t* p__parent = 0, pcx_t* p__root = 0);

    private:
        void _read();

    public:
        ~header_t();

    private:
        std::string m_magic;
        versions_t m_version;
        encodings_t m_encoding;
        uint8_t m_bits_per_pixel;
        uint16_t m_img_x_min;
        uint16_t m_img_y_min;
        uint16_t m_img_x_max;
        uint16_t m_img_y_max;
        uint16_t m_hdpi;
        uint16_t m_vdpi;
        std::string m_palette_16;
        std::string m_reserved;
        uint8_t m_num_planes;
        uint16_t m_bytes_per_line;
        uint16_t m_palette_info;
        uint16_t m_h_screen_size;
        uint16_t m_v_screen_size;
        pcx_t* m__root;
        pcx_t* m__parent;

    public:

        /**
         * Technically, this field was supposed to be "manufacturer"
         * mark to distinguish between various software vendors, and
         * 0x0a was supposed to mean "ZSoft", but everyone else ended
         * up writing a 0x0a into this field, so that's what majority
         * of modern software expects to have in this attribute.
         */
        std::string magic() const { return m_magic; }
        versions_t version() const { return m_version; }
        encodings_t encoding() const { return m_encoding; }
        uint8_t bits_per_pixel() const { return m_bits_per_pixel; }
        uint16_t img_x_min() const { return m_img_x_min; }
        uint16_t img_y_min() const { return m_img_y_min; }
        uint16_t img_x_max() const { return m_img_x_max; }
        uint16_t img_y_max() const { return m_img_y_max; }
        uint16_t hdpi() const { return m_hdpi; }
        uint16_t vdpi() const { return m_vdpi; }
        std::string palette_16() const { return m_palette_16; }
        std::string reserved() const { return m_reserved; }
        uint8_t num_planes() const { return m_num_planes; }
        uint16_t bytes_per_line() const { return m_bytes_per_line; }
        uint16_t palette_info() const { return m_palette_info; }
        uint16_t h_screen_size() const { return m_h_screen_size; }
        uint16_t v_screen_size() const { return m_v_screen_size; }
        pcx_t* _root() const { return m__root; }
        pcx_t* _parent() const { return m__parent; }
    };

    class t_palette_256_t : public kaitai::kstruct {

    public:

        t_palette_256_t(kaitai::kstream* p__io, pcx_t* p__parent = 0, pcx_t* p__root = 0);

    private:
        void _read();

    public:
        ~t_palette_256_t();

    private:
        std::string m_magic;
        std::vector<rgb_t*>* m_colors;
        pcx_t* m__root;
        pcx_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        std::vector<rgb_t*>* colors() const { return m_colors; }
        pcx_t* _root() const { return m__root; }
        pcx_t* _parent() const { return m__parent; }
    };

    class rgb_t : public kaitai::kstruct {

    public:

        rgb_t(kaitai::kstream* p__io, pcx_t::t_palette_256_t* p__parent = 0, pcx_t* p__root = 0);

    private:
        void _read();

    public:
        ~rgb_t();

    private:
        uint8_t m_r;
        uint8_t m_g;
        uint8_t m_b;
        pcx_t* m__root;
        pcx_t::t_palette_256_t* m__parent;

    public:
        uint8_t r() const { return m_r; }
        uint8_t g() const { return m_g; }
        uint8_t b() const { return m_b; }
        pcx_t* _root() const { return m__root; }
        pcx_t::t_palette_256_t* _parent() const { return m__parent; }
    };

private:
    bool f_palette_256;
    t_palette_256_t* m_palette_256;
    bool n_palette_256;

public:
    bool _is_null_palette_256() { palette_256(); return n_palette_256; };

private:

public:

    /**
     * \sa - "VGA 256 Color Palette Information"
     */
    t_palette_256_t* palette_256();

private:
    header_t* m_hdr;
    pcx_t* m__root;
    kaitai::kstruct* m__parent;
    std::string m__raw_hdr;
    kaitai::kstream* m__io__raw_hdr;

public:
    header_t* hdr() const { return m_hdr; }
    pcx_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::string _raw_hdr() const { return m__raw_hdr; }
    kaitai::kstream* _io__raw_hdr() const { return m__io__raw_hdr; }
};

#endif  // PCX_H_

pcx.cpp

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

#include "pcx.h"



pcx_t::pcx_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, pcx_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    f_palette_256 = false;
    _read();
}

void pcx_t::_read() {
    m__raw_hdr = m__io->read_bytes(128);
    m__io__raw_hdr = new kaitai::kstream(m__raw_hdr);
    m_hdr = new header_t(m__io__raw_hdr, this, m__root);
}

pcx_t::~pcx_t() {
    delete m__io__raw_hdr;
    delete m_hdr;
    if (f_palette_256 && !n_palette_256) {
        delete m_palette_256;
    }
}

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

void pcx_t::header_t::_read() {
    m_magic = m__io->ensure_fixed_contents(std::string("\x0A", 1));
    m_version = static_cast<pcx_t::versions_t>(m__io->read_u1());
    m_encoding = static_cast<pcx_t::encodings_t>(m__io->read_u1());
    m_bits_per_pixel = m__io->read_u1();
    m_img_x_min = m__io->read_u2le();
    m_img_y_min = m__io->read_u2le();
    m_img_x_max = m__io->read_u2le();
    m_img_y_max = m__io->read_u2le();
    m_hdpi = m__io->read_u2le();
    m_vdpi = m__io->read_u2le();
    m_palette_16 = m__io->read_bytes(48);
    m_reserved = m__io->ensure_fixed_contents(std::string("\x00", 1));
    m_num_planes = m__io->read_u1();
    m_bytes_per_line = m__io->read_u2le();
    m_palette_info = m__io->read_u2le();
    m_h_screen_size = m__io->read_u2le();
    m_v_screen_size = m__io->read_u2le();
}

pcx_t::header_t::~header_t() {
}

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

void pcx_t::t_palette_256_t::_read() {
    m_magic = m__io->ensure_fixed_contents(std::string("\x0C", 1));
    int l_colors = 256;
    m_colors = new std::vector<rgb_t*>();
    m_colors->reserve(l_colors);
    for (int i = 0; i < l_colors; i++) {
        m_colors->push_back(new rgb_t(m__io, this, m__root));
    }
}

pcx_t::t_palette_256_t::~t_palette_256_t() {
    for (std::vector<rgb_t*>::iterator it = m_colors->begin(); it != m_colors->end(); ++it) {
        delete *it;
    }
    delete m_colors;
}

pcx_t::rgb_t::rgb_t(kaitai::kstream* p__io, pcx_t::t_palette_256_t* p__parent, pcx_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void pcx_t::rgb_t::_read() {
    m_r = m__io->read_u1();
    m_g = m__io->read_u1();
    m_b = m__io->read_u1();
}

pcx_t::rgb_t::~rgb_t() {
}

pcx_t::t_palette_256_t* pcx_t::palette_256() {
    if (f_palette_256)
        return m_palette_256;
    n_palette_256 = true;
    if ( ((hdr()->version() == VERSIONS_V3_0) && (hdr()->bits_per_pixel() == 8) && (hdr()->num_planes() == 1)) ) {
        n_palette_256 = false;
        std::streampos _pos = m__io->pos();
        m__io->seek((_io()->size() - 769));
        m_palette_256 = new t_palette_256_t(m__io, this, m__root);
        m__io->seek(_pos);
    }
    f_palette_256 = true;
    return m_palette_256;
}