Windows Metafile (WMF) vector image: C++98/STL parsing library

WMF (Windows Metafile) is a relatively early vector image format introduced for Microsoft Windows in 1990.

Inside, it provides a serialized list of Windows GDI (Graphics Device Interface) function calls, which, if played back, result in an image being drawn on a given surface (display, off-screen buffer, printer, etc).

File extension

wmf

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of Windows Metafile (WMF) vector image 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.wmf", 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:
    wmf_t data(&ks);
    

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

data.special_header() // => get special header

C++98/STL source code to parse Windows Metafile (WMF) vector image

wmf.h

#ifndef WMF_H_
#define WMF_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

/**
 * WMF (Windows Metafile) is a relatively early vector image format
 * introduced for Microsoft Windows in 1990.
 * 
 * Inside, it provides a serialized list of Windows GDI (Graphics
 * Device Interface) function calls, which, if played back, result in
 * an image being drawn on a given surface (display, off-screen buffer,
 * printer, etc).
 * \sa https://www.loc.gov/preservation/digital/formats/digformatspecs/WindowsMetafileFormat(wmf)Specification.pdf Source
 */

class wmf_t : public kaitai::kstruct {

public:
    class params_setwindoworg_t;
    class params_setbkmode_t;
    class point_s_t;
    class params_setwindowext_t;
    class params_polygon_t;
    class header_t;
    class color_ref_t;
    class params_setrop2_t;
    class params_setpolyfillmode_t;
    class params_polyline_t;
    class special_header_t;
    class record_t;

    enum func_t {
        FUNC_EOF = 0,
        FUNC_SAVEDC = 30,
        FUNC_REALIZEPALETTE = 53,
        FUNC_SETPALENTRIES = 55,
        FUNC_CREATEPALETTE = 247,
        FUNC_SETBKMODE = 258,
        FUNC_SETMAPMODE = 259,
        FUNC_SETROP2 = 260,
        FUNC_SETRELABS = 261,
        FUNC_SETPOLYFILLMODE = 262,
        FUNC_SETSTRETCHBLTMODE = 263,
        FUNC_SETTEXTCHAREXTRA = 264,
        FUNC_RESTOREDC = 295,
        FUNC_INVERTREGION = 298,
        FUNC_PAINTREGION = 299,
        FUNC_SELECTCLIPREGION = 300,
        FUNC_SELECTOBJECT = 301,
        FUNC_SETTEXTALIGN = 302,
        FUNC_RESIZEPALETTE = 313,
        FUNC_DIBCREATEPATTERNBRUSH = 322,
        FUNC_SETLAYOUT = 329,
        FUNC_DELETEOBJECT = 496,
        FUNC_CREATEPATTERNBRUSH = 505,
        FUNC_SETBKCOLOR = 513,
        FUNC_SETTEXTCOLOR = 521,
        FUNC_SETTEXTJUSTIFICATION = 522,
        FUNC_SETWINDOWORG = 523,
        FUNC_SETWINDOWEXT = 524,
        FUNC_SETVIEWPORTORG = 525,
        FUNC_SETVIEWPORTEXT = 526,
        FUNC_OFFSETWINDOWORG = 527,
        FUNC_OFFSETVIEWPORTORG = 529,
        FUNC_LINETO = 531,
        FUNC_MOVETO = 532,
        FUNC_OFFSETCLIPRGN = 544,
        FUNC_FILLREGION = 552,
        FUNC_SETMAPPERFLAGS = 561,
        FUNC_SELECTPALETTE = 564,
        FUNC_CREATEPENINDIRECT = 762,
        FUNC_CREATEFONTINDIRECT = 763,
        FUNC_CREATEBRUSHINDIRECT = 764,
        FUNC_POLYGON = 804,
        FUNC_POLYLINE = 805,
        FUNC_SCALEWINDOWEXT = 1040,
        FUNC_SCALEVIEWPORTEXT = 1042,
        FUNC_EXCLUDECLIPRECT = 1045,
        FUNC_INTERSECTCLIPRECT = 1046,
        FUNC_ELLIPSE = 1048,
        FUNC_FLOODFILL = 1049,
        FUNC_RECTANGLE = 1051,
        FUNC_SETPIXEL = 1055,
        FUNC_FRAMEREGION = 1065,
        FUNC_ANIMATEPALETTE = 1078,
        FUNC_TEXTOUT = 1313,
        FUNC_POLYPOLYGON = 1336,
        FUNC_EXTFLOODFILL = 1352,
        FUNC_ROUNDRECT = 1564,
        FUNC_PATBLT = 1565,
        FUNC_ESCAPE = 1574,
        FUNC_CREATEREGION = 1791,
        FUNC_ARC = 2071,
        FUNC_PIE = 2074,
        FUNC_CHORD = 2096,
        FUNC_BITBLT = 2338,
        FUNC_DIBBITBLT = 2368,
        FUNC_EXTTEXTOUT = 2610,
        FUNC_STRETCHBLT = 2851,
        FUNC_DIBSTRETCHBLT = 2881,
        FUNC_SETDIBTODEV = 3379,
        FUNC_STRETCHDIB = 3907
    };

    enum bin_raster_op_t {
        BIN_RASTER_OP_BLACK = 1,
        BIN_RASTER_OP_NOTMERGEPEN = 2,
        BIN_RASTER_OP_MASKNOTPEN = 3,
        BIN_RASTER_OP_NOTCOPYPEN = 4,
        BIN_RASTER_OP_MASKPENNOT = 5,
        BIN_RASTER_OP_NOT = 6,
        BIN_RASTER_OP_XORPEN = 7,
        BIN_RASTER_OP_NOTMASKPEN = 8,
        BIN_RASTER_OP_MASKPEN = 9,
        BIN_RASTER_OP_NOTXORPEN = 10,
        BIN_RASTER_OP_NOP = 11,
        BIN_RASTER_OP_MERGENOTPEN = 12,
        BIN_RASTER_OP_COPYPEN = 13,
        BIN_RASTER_OP_MERGEPENNOT = 14,
        BIN_RASTER_OP_MERGEPEN = 15,
        BIN_RASTER_OP_WHITE = 16
    };

    enum mix_mode_t {
        MIX_MODE_TRANSPARENT = 1,
        MIX_MODE_OPAQUE = 2
    };

    enum poly_fill_mode_t {
        POLY_FILL_MODE_ALTERNATE = 1,
        POLY_FILL_MODE_WINDING = 2
    };

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

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

public:
    ~wmf_t();

    /**
     * \sa section 2.3.5.31
     */

    class params_setwindoworg_t : public kaitai::kstruct {

    public:

        params_setwindoworg_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_setwindoworg_t();

    private:
        int16_t m_y;
        int16_t m_x;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:

        /**
         * Y coordinate of the window origin, in logical units.
         */
        int16_t y() const { return m_y; }

        /**
         * X coordinate of the window origin, in logical units.
         */
        int16_t x() const { return m_x; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.3.5.15
     */

    class params_setbkmode_t : public kaitai::kstruct {

    public:

        params_setbkmode_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_setbkmode_t();

    private:
        mix_mode_t m_bk_mode;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:

        /**
         * Defines current graphic context background mix mode.
         */
        mix_mode_t bk_mode() const { return m_bk_mode; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.2.1.12
     */

    class point_s_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~point_s_t();

    private:
        int16_t m_x;
        int16_t m_y;
        wmf_t* m__root;
        kaitai::kstruct* m__parent;

    public:

        /**
         * X coordinate of the point, in logical units.
         */
        int16_t x() const { return m_x; }

        /**
         * Y coordinate of the point, in logical units.
         */
        int16_t y() const { return m_y; }
        wmf_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.3.5.30
     */

    class params_setwindowext_t : public kaitai::kstruct {

    public:

        params_setwindowext_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_setwindowext_t();

    private:
        int16_t m_y;
        int16_t m_x;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:

        /**
         * Vertical extent of the window in logical units.
         */
        int16_t y() const { return m_y; }

        /**
         * Horizontal extent of the window in logical units.
         */
        int16_t x() const { return m_x; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.3.3.15 = params_polyline
     */

    class params_polygon_t : public kaitai::kstruct {

    public:

        params_polygon_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_polygon_t();

    private:
        int16_t m_num_points;
        std::vector<point_s_t*>* m_points;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:
        int16_t num_points() const { return m_num_points; }
        std::vector<point_s_t*>* points() const { return m_points; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    class header_t : public kaitai::kstruct {

    public:

        enum metafile_type_t {
            METAFILE_TYPE_MEMORY_METAFILE = 1,
            METAFILE_TYPE_DISK_METAFILE = 2
        };

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

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

    public:
        ~header_t();

    private:
        metafile_type_t m_metafile_type;
        uint16_t m_header_size;
        uint16_t m_version;
        uint32_t m_size;
        uint16_t m_number_of_objects;
        uint32_t m_max_record;
        uint16_t m_number_of_members;
        wmf_t* m__root;
        wmf_t* m__parent;

    public:
        metafile_type_t metafile_type() const { return m_metafile_type; }
        uint16_t header_size() const { return m_header_size; }
        uint16_t version() const { return m_version; }
        uint32_t size() const { return m_size; }
        uint16_t number_of_objects() const { return m_number_of_objects; }
        uint32_t max_record() const { return m_max_record; }
        uint16_t number_of_members() const { return m_number_of_members; }
        wmf_t* _root() const { return m__root; }
        wmf_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.2.1.7
     */

    class color_ref_t : public kaitai::kstruct {

    public:

        color_ref_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~color_ref_t();

    private:
        uint8_t m_red;
        uint8_t m_green;
        uint8_t m_blue;
        uint8_t m_reserved;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:
        uint8_t red() const { return m_red; }
        uint8_t green() const { return m_green; }
        uint8_t blue() const { return m_blue; }
        uint8_t reserved() const { return m_reserved; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.3.5.22
     */

    class params_setrop2_t : public kaitai::kstruct {

    public:

        params_setrop2_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_setrop2_t();

    private:
        bin_raster_op_t m_draw_mode;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:

        /**
         * Defines current foreground binary raster operation mixing mode.
         */
        bin_raster_op_t draw_mode() const { return m_draw_mode; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.3.5.20
     */

    class params_setpolyfillmode_t : public kaitai::kstruct {

    public:

        params_setpolyfillmode_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_setpolyfillmode_t();

    private:
        poly_fill_mode_t m_poly_fill_mode;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:

        /**
         * Defines current polygon fill mode.
         */
        poly_fill_mode_t poly_fill_mode() const { return m_poly_fill_mode; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    /**
     * \sa section 2.3.3.14
     */

    class params_polyline_t : public kaitai::kstruct {

    public:

        params_polyline_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~params_polyline_t();

    private:
        int16_t m_num_points;
        std::vector<point_s_t*>* m_points;
        wmf_t* m__root;
        wmf_t::record_t* m__parent;

    public:
        int16_t num_points() const { return m_num_points; }
        std::vector<point_s_t*>* points() const { return m_points; }
        wmf_t* _root() const { return m__root; }
        wmf_t::record_t* _parent() const { return m__parent; }
    };

    class special_header_t : public kaitai::kstruct {

    public:

        special_header_t(kaitai::kstream* p__io, wmf_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~special_header_t();

    private:
        std::string m_magic;
        std::string m_handle;
        int16_t m_left;
        int16_t m_top;
        int16_t m_right;
        int16_t m_bottom;
        uint16_t m_inch;
        std::string m_reserved;
        uint16_t m_checksum;
        wmf_t* m__root;
        wmf_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        std::string handle() const { return m_handle; }
        int16_t left() const { return m_left; }
        int16_t top() const { return m_top; }
        int16_t right() const { return m_right; }
        int16_t bottom() const { return m_bottom; }
        uint16_t inch() const { return m_inch; }
        std::string reserved() const { return m_reserved; }
        uint16_t checksum() const { return m_checksum; }
        wmf_t* _root() const { return m__root; }
        wmf_t* _parent() const { return m__parent; }
    };

    class record_t : public kaitai::kstruct {

    public:

        record_t(kaitai::kstream* p__io, wmf_t* p__parent = 0, wmf_t* p__root = 0);

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

    public:
        ~record_t();

    private:
        uint32_t m_size;
        func_t m_function;
        kaitai::kstruct* m_params;
        bool n_params;

    public:
        bool _is_null_params() { params(); return n_params; };

    private:
        wmf_t* m__root;
        wmf_t* m__parent;
        std::string m__raw_params;
        kaitai::kstream* m__io__raw_params;

    public:
        uint32_t size() const { return m_size; }
        func_t function() const { return m_function; }
        kaitai::kstruct* params() const { return m_params; }
        wmf_t* _root() const { return m__root; }
        wmf_t* _parent() const { return m__parent; }
        std::string _raw_params() const { return m__raw_params; }
        kaitai::kstream* _io__raw_params() const { return m__io__raw_params; }
    };

private:
    special_header_t* m_special_header;
    header_t* m_header;
    std::vector<record_t*>* m_records;
    wmf_t* m__root;
    kaitai::kstruct* m__parent;

public:
    special_header_t* special_header() const { return m_special_header; }
    header_t* header() const { return m_header; }
    std::vector<record_t*>* records() const { return m_records; }
    wmf_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // WMF_H_

wmf.cpp

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

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

wmf_t::wmf_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_special_header = 0;
    m_header = 0;
    m_records = 0;

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

void wmf_t::_read() {
    m_special_header = new special_header_t(m__io, this, m__root);
    m_header = new header_t(m__io, this, m__root);
    m_records = new std::vector<record_t*>();
    {
        int i = 0;
        record_t* _;
        do {
            _ = new record_t(m__io, this, m__root);
            m_records->push_back(_);
            i++;
        } while (!(_->function() == wmf_t::FUNC_EOF));
    }
}

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

void wmf_t::_clean_up() {
    if (m_special_header) {
        delete m_special_header; m_special_header = 0;
    }
    if (m_header) {
        delete m_header; m_header = 0;
    }
    if (m_records) {
        for (std::vector<record_t*>::iterator it = m_records->begin(); it != m_records->end(); ++it) {
            delete *it;
        }
        delete m_records; m_records = 0;
    }
}

wmf_t::params_setwindoworg_t::params_setwindoworg_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void wmf_t::params_setwindoworg_t::_read() {
    m_y = m__io->read_s2le();
    m_x = m__io->read_s2le();
}

wmf_t::params_setwindoworg_t::~params_setwindoworg_t() {
    _clean_up();
}

void wmf_t::params_setwindoworg_t::_clean_up() {
}

wmf_t::params_setbkmode_t::params_setbkmode_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void wmf_t::params_setbkmode_t::_read() {
    m_bk_mode = static_cast<wmf_t::mix_mode_t>(m__io->read_u2le());
}

wmf_t::params_setbkmode_t::~params_setbkmode_t() {
    _clean_up();
}

void wmf_t::params_setbkmode_t::_clean_up() {
}

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

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

void wmf_t::point_s_t::_read() {
    m_x = m__io->read_s2le();
    m_y = m__io->read_s2le();
}

wmf_t::point_s_t::~point_s_t() {
    _clean_up();
}

void wmf_t::point_s_t::_clean_up() {
}

wmf_t::params_setwindowext_t::params_setwindowext_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void wmf_t::params_setwindowext_t::_read() {
    m_y = m__io->read_s2le();
    m_x = m__io->read_s2le();
}

wmf_t::params_setwindowext_t::~params_setwindowext_t() {
    _clean_up();
}

void wmf_t::params_setwindowext_t::_clean_up() {
}

wmf_t::params_polygon_t::params_polygon_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_points = 0;

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

void wmf_t::params_polygon_t::_read() {
    m_num_points = m__io->read_s2le();
    m_points = new std::vector<point_s_t*>();
    const int l_points = num_points();
    for (int i = 0; i < l_points; i++) {
        m_points->push_back(new point_s_t(m__io, this, m__root));
    }
}

wmf_t::params_polygon_t::~params_polygon_t() {
    _clean_up();
}

void wmf_t::params_polygon_t::_clean_up() {
    if (m_points) {
        for (std::vector<point_s_t*>::iterator it = m_points->begin(); it != m_points->end(); ++it) {
            delete *it;
        }
        delete m_points; m_points = 0;
    }
}

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

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

void wmf_t::header_t::_read() {
    m_metafile_type = static_cast<wmf_t::header_t::metafile_type_t>(m__io->read_u2le());
    m_header_size = m__io->read_u2le();
    m_version = m__io->read_u2le();
    m_size = m__io->read_u4le();
    m_number_of_objects = m__io->read_u2le();
    m_max_record = m__io->read_u4le();
    m_number_of_members = m__io->read_u2le();
}

wmf_t::header_t::~header_t() {
    _clean_up();
}

void wmf_t::header_t::_clean_up() {
}

wmf_t::color_ref_t::color_ref_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void wmf_t::color_ref_t::_read() {
    m_red = m__io->read_u1();
    m_green = m__io->read_u1();
    m_blue = m__io->read_u1();
    m_reserved = m__io->read_u1();
}

wmf_t::color_ref_t::~color_ref_t() {
    _clean_up();
}

void wmf_t::color_ref_t::_clean_up() {
}

wmf_t::params_setrop2_t::params_setrop2_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void wmf_t::params_setrop2_t::_read() {
    m_draw_mode = static_cast<wmf_t::bin_raster_op_t>(m__io->read_u2le());
}

wmf_t::params_setrop2_t::~params_setrop2_t() {
    _clean_up();
}

void wmf_t::params_setrop2_t::_clean_up() {
}

wmf_t::params_setpolyfillmode_t::params_setpolyfillmode_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void wmf_t::params_setpolyfillmode_t::_read() {
    m_poly_fill_mode = static_cast<wmf_t::poly_fill_mode_t>(m__io->read_u2le());
}

wmf_t::params_setpolyfillmode_t::~params_setpolyfillmode_t() {
    _clean_up();
}

void wmf_t::params_setpolyfillmode_t::_clean_up() {
}

wmf_t::params_polyline_t::params_polyline_t(kaitai::kstream* p__io, wmf_t::record_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_points = 0;

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

void wmf_t::params_polyline_t::_read() {
    m_num_points = m__io->read_s2le();
    m_points = new std::vector<point_s_t*>();
    const int l_points = num_points();
    for (int i = 0; i < l_points; i++) {
        m_points->push_back(new point_s_t(m__io, this, m__root));
    }
}

wmf_t::params_polyline_t::~params_polyline_t() {
    _clean_up();
}

void wmf_t::params_polyline_t::_clean_up() {
    if (m_points) {
        for (std::vector<point_s_t*>::iterator it = m_points->begin(); it != m_points->end(); ++it) {
            delete *it;
        }
        delete m_points; m_points = 0;
    }
}

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

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

void wmf_t::special_header_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\xD7\xCD\xC6\x9A", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\xD7\xCD\xC6\x9A", 4), magic(), _io(), std::string("/types/special_header/seq/0"));
    }
    m_handle = m__io->read_bytes(2);
    if (!(handle() == std::string("\x00\x00", 2))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\x00", 2), handle(), _io(), std::string("/types/special_header/seq/1"));
    }
    m_left = m__io->read_s2le();
    m_top = m__io->read_s2le();
    m_right = m__io->read_s2le();
    m_bottom = m__io->read_s2le();
    m_inch = m__io->read_u2le();
    m_reserved = m__io->read_bytes(4);
    if (!(reserved() == std::string("\x00\x00\x00\x00", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\x00\x00\x00", 4), reserved(), _io(), std::string("/types/special_header/seq/7"));
    }
    m_checksum = m__io->read_u2le();
}

wmf_t::special_header_t::~special_header_t() {
    _clean_up();
}

void wmf_t::special_header_t::_clean_up() {
}

wmf_t::record_t::record_t(kaitai::kstream* p__io, wmf_t* p__parent, wmf_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_params = 0;

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

void wmf_t::record_t::_read() {
    m_size = m__io->read_u4le();
    m_function = static_cast<wmf_t::func_t>(m__io->read_u2le());
    n_params = true;
    switch (function()) {
    case wmf_t::FUNC_SETBKMODE: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_setbkmode_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_POLYGON: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_polygon_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_SETBKCOLOR: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new color_ref_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_SETPOLYFILLMODE: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_setpolyfillmode_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_SETWINDOWORG: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_setwindoworg_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_SETROP2: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_setrop2_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_SETWINDOWEXT: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_setwindowext_t(m__io__raw_params, this, m__root);
        break;
    }
    case wmf_t::FUNC_POLYLINE: {
        n_params = false;
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        m__io__raw_params = new kaitai::kstream(m__raw_params);
        m_params = new params_polyline_t(m__io__raw_params, this, m__root);
        break;
    }
    default: {
        m__raw_params = m__io->read_bytes(((size() - 3) * 2));
        break;
    }
    }
}

wmf_t::record_t::~record_t() {
    _clean_up();
}

void wmf_t::record_t::_clean_up() {
    if (!n_params) {
        if (m__io__raw_params) {
            delete m__io__raw_params; m__io__raw_params = 0;
        }
        if (m_params) {
            delete m_params; m_params = 0;
        }
    }
}