.wad file format of id Tech 1: C++11/STL parsing library

Application

id Tech 1

File extension

wad

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of .wad file format of id Tech 1 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.wad", 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:
    doom_wad_t data(&ks);
    

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

data.num_index_entries() // => Number of entries in the lump index

C++11/STL source code to parse .wad file format of id Tech 1

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

class doom_wad_t : public kaitai::kstruct {

public:
    class sectors_t;
    class vertex_t;
    class texture12_t;
    class linedef_t;
    class pnames_t;
    class thing_t;
    class sector_t;
    class vertexes_t;
    class sidedef_t;
    class things_t;
    class linedefs_t;
    class index_entry_t;
    class sidedefs_t;
    class blockmap_t;

    doom_wad_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

public:
    ~doom_wad_t();

    class sectors_t : public kaitai::kstruct {

    public:

        sectors_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~sectors_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<sector_t>>> m_entries;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:
        std::vector<std::unique_ptr<sector_t>>* entries() const { return m_entries.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class vertex_t : public kaitai::kstruct {

    public:

        vertex_t(kaitai::kstream* p__io, doom_wad_t::vertexes_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~vertex_t();

    private:
        int16_t m_x;
        int16_t m_y;
        doom_wad_t* m__root;
        doom_wad_t::vertexes_t* m__parent;

    public:
        int16_t x() const { return m_x; }
        int16_t y() const { return m_y; }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::vertexes_t* _parent() const { return m__parent; }
    };

    /**
     * Used for TEXTURE1 and TEXTURE2 lumps, which designate how to
     * combine wall patches to make wall textures. This essentially
     * provides a very simple form of image compression, allowing
     * certain elements ("patches") to be reused / recombined on
     * different textures for more variety in the game.
     * \sa https://doom.fandom.com/wiki/TEXTURE1_and_TEXTURE2 Source
     */

    class texture12_t : public kaitai::kstruct {

    public:
        class texture_index_t;
        class texture_body_t;
        class patch_t;

        texture12_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~texture12_t();

        class texture_index_t : public kaitai::kstruct {

        public:

            texture_index_t(kaitai::kstream* p__io, doom_wad_t::texture12_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

        public:
            ~texture_index_t();

        private:
            bool f_body;
            std::unique_ptr<texture_body_t> m_body;

        public:
            texture_body_t* body();

        private:
            int32_t m_offset;
            doom_wad_t* m__root;
            doom_wad_t::texture12_t* m__parent;

        public:
            int32_t offset() const { return m_offset; }
            doom_wad_t* _root() const { return m__root; }
            doom_wad_t::texture12_t* _parent() const { return m__parent; }
        };

        class texture_body_t : public kaitai::kstruct {

        public:

            texture_body_t(kaitai::kstream* p__io, doom_wad_t::texture12_t::texture_index_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

        public:
            ~texture_body_t();

        private:
            std::string m_name;
            uint32_t m_masked;
            uint16_t m_width;
            uint16_t m_height;
            uint32_t m_column_directory;
            uint16_t m_num_patches;
            std::unique_ptr<std::vector<std::unique_ptr<patch_t>>> m_patches;
            doom_wad_t* m__root;
            doom_wad_t::texture12_t::texture_index_t* m__parent;

        public:

            /**
             * Name of a texture, only `A-Z`, `0-9`, `[]_-` are valid
             */
            std::string name() const { return m_name; }
            uint32_t masked() const { return m_masked; }
            uint16_t width() const { return m_width; }
            uint16_t height() const { return m_height; }

            /**
             * Obsolete, ignored by all DOOM versions
             */
            uint32_t column_directory() const { return m_column_directory; }

            /**
             * Number of patches that are used in a texture
             */
            uint16_t num_patches() const { return m_num_patches; }
            std::vector<std::unique_ptr<patch_t>>* patches() const { return m_patches.get(); }
            doom_wad_t* _root() const { return m__root; }
            doom_wad_t::texture12_t::texture_index_t* _parent() const { return m__parent; }
        };

        class patch_t : public kaitai::kstruct {

        public:

            patch_t(kaitai::kstream* p__io, doom_wad_t::texture12_t::texture_body_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

        public:
            ~patch_t();

        private:
            int16_t m_origin_x;
            int16_t m_origin_y;
            uint16_t m_patch_id;
            uint16_t m_step_dir;
            uint16_t m_colormap;
            doom_wad_t* m__root;
            doom_wad_t::texture12_t::texture_body_t* m__parent;

        public:

            /**
             * X offset to draw a patch at (pixels from left boundary of a texture)
             */
            int16_t origin_x() const { return m_origin_x; }

            /**
             * Y offset to draw a patch at (pixels from upper boundary of a texture)
             */
            int16_t origin_y() const { return m_origin_y; }

            /**
             * Identifier of a patch (as listed in PNAMES lump) to draw
             */
            uint16_t patch_id() const { return m_patch_id; }
            uint16_t step_dir() const { return m_step_dir; }
            uint16_t colormap() const { return m_colormap; }
            doom_wad_t* _root() const { return m__root; }
            doom_wad_t::texture12_t::texture_body_t* _parent() const { return m__parent; }
        };

    private:
        int32_t m_num_textures;
        std::unique_ptr<std::vector<std::unique_ptr<texture_index_t>>> m_textures;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:

        /**
         * Number of wall textures
         */
        int32_t num_textures() const { return m_num_textures; }
        std::vector<std::unique_ptr<texture_index_t>>* textures() const { return m_textures.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class linedef_t : public kaitai::kstruct {

    public:

        linedef_t(kaitai::kstream* p__io, doom_wad_t::linedefs_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~linedef_t();

    private:
        uint16_t m_vertex_start_idx;
        uint16_t m_vertex_end_idx;
        uint16_t m_flags;
        uint16_t m_line_type;
        uint16_t m_sector_tag;
        uint16_t m_sidedef_right_idx;
        uint16_t m_sidedef_left_idx;
        doom_wad_t* m__root;
        doom_wad_t::linedefs_t* m__parent;

    public:
        uint16_t vertex_start_idx() const { return m_vertex_start_idx; }
        uint16_t vertex_end_idx() const { return m_vertex_end_idx; }
        uint16_t flags() const { return m_flags; }
        uint16_t line_type() const { return m_line_type; }
        uint16_t sector_tag() const { return m_sector_tag; }
        uint16_t sidedef_right_idx() const { return m_sidedef_right_idx; }
        uint16_t sidedef_left_idx() const { return m_sidedef_left_idx; }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::linedefs_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://doom.fandom.com/wiki/PNAMES Source
     */

    class pnames_t : public kaitai::kstruct {

    public:

        pnames_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~pnames_t();

    private:
        uint32_t m_num_patches;
        std::unique_ptr<std::vector<std::string>> m_names;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:

        /**
         * Number of patches registered in this global game directory
         */
        uint32_t num_patches() const { return m_num_patches; }
        std::vector<std::string>* names() const { return m_names.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class thing_t : public kaitai::kstruct {

    public:

        thing_t(kaitai::kstream* p__io, doom_wad_t::things_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~thing_t();

    private:
        int16_t m_x;
        int16_t m_y;
        uint16_t m_angle;
        uint16_t m_type;
        uint16_t m_flags;
        doom_wad_t* m__root;
        doom_wad_t::things_t* m__parent;

    public:
        int16_t x() const { return m_x; }
        int16_t y() const { return m_y; }
        uint16_t angle() const { return m_angle; }
        uint16_t type() const { return m_type; }
        uint16_t flags() const { return m_flags; }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::things_t* _parent() const { return m__parent; }
    };

    class sector_t : public kaitai::kstruct {

    public:

        enum special_sector_t {
            SPECIAL_SECTOR_NORMAL = 0,
            SPECIAL_SECTOR_D_LIGHT_FLICKER = 1,
            SPECIAL_SECTOR_D_LIGHT_STROBE_FAST = 2,
            SPECIAL_SECTOR_D_LIGHT_STROBE_SLOW = 3,
            SPECIAL_SECTOR_D_LIGHT_STROBE_HURT = 4,
            SPECIAL_SECTOR_D_DAMAGE_HELLSLIME = 5,
            SPECIAL_SECTOR_D_DAMAGE_NUKAGE = 7,
            SPECIAL_SECTOR_D_LIGHT_GLOW = 8,
            SPECIAL_SECTOR_SECRET = 9,
            SPECIAL_SECTOR_D_SECTOR_DOOR_CLOSE_IN_30 = 10,
            SPECIAL_SECTOR_D_DAMAGE_END = 11,
            SPECIAL_SECTOR_D_LIGHT_STROBE_SLOW_SYNC = 12,
            SPECIAL_SECTOR_D_LIGHT_STROBE_FAST_SYNC = 13,
            SPECIAL_SECTOR_D_SECTOR_DOOR_RAISE_IN_5_MINS = 14,
            SPECIAL_SECTOR_D_FRICTION_LOW = 15,
            SPECIAL_SECTOR_D_DAMAGE_SUPER_HELLSLIME = 16,
            SPECIAL_SECTOR_D_LIGHT_FIRE_FLICKER = 17,
            SPECIAL_SECTOR_D_DAMAGE_LAVA_WIMPY = 18,
            SPECIAL_SECTOR_D_DAMAGE_LAVA_HEFTY = 19,
            SPECIAL_SECTOR_D_SCROLL_EAST_LAVA_DAMAGE = 20,
            SPECIAL_SECTOR_LIGHT_PHASED = 21,
            SPECIAL_SECTOR_LIGHT_SEQUENCE_START = 22,
            SPECIAL_SECTOR_LIGHT_SEQUENCE_SPECIAL1 = 23,
            SPECIAL_SECTOR_LIGHT_SEQUENCE_SPECIAL2 = 24
        };

        sector_t(kaitai::kstream* p__io, doom_wad_t::sectors_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~sector_t();

    private:
        int16_t m_floor_z;
        int16_t m_ceil_z;
        std::string m_floor_flat;
        std::string m_ceil_flat;
        int16_t m_light;
        special_sector_t m_special_type;
        uint16_t m_tag;
        doom_wad_t* m__root;
        doom_wad_t::sectors_t* m__parent;

    public:
        int16_t floor_z() const { return m_floor_z; }
        int16_t ceil_z() const { return m_ceil_z; }
        std::string floor_flat() const { return m_floor_flat; }
        std::string ceil_flat() const { return m_ceil_flat; }

        /**
         * Light level of the sector [0..255]. Original engine uses
         * COLORMAP to render lighting, so only 32 actual levels are
         * available (i.e. 0..7, 8..15, etc).
         */
        int16_t light() const { return m_light; }
        special_sector_t special_type() const { return m_special_type; }

        /**
         * Tag number. When the linedef with the same tag number is
         * activated, some effect will be triggered in this sector.
         */
        uint16_t tag() const { return m_tag; }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::sectors_t* _parent() const { return m__parent; }
    };

    class vertexes_t : public kaitai::kstruct {

    public:

        vertexes_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~vertexes_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<vertex_t>>> m_entries;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:
        std::vector<std::unique_ptr<vertex_t>>* entries() const { return m_entries.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class sidedef_t : public kaitai::kstruct {

    public:

        sidedef_t(kaitai::kstream* p__io, doom_wad_t::sidedefs_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~sidedef_t();

    private:
        int16_t m_offset_x;
        int16_t m_offset_y;
        std::string m_upper_texture_name;
        std::string m_lower_texture_name;
        std::string m_normal_texture_name;
        int16_t m_sector_id;
        doom_wad_t* m__root;
        doom_wad_t::sidedefs_t* m__parent;

    public:
        int16_t offset_x() const { return m_offset_x; }
        int16_t offset_y() const { return m_offset_y; }
        std::string upper_texture_name() const { return m_upper_texture_name; }
        std::string lower_texture_name() const { return m_lower_texture_name; }
        std::string normal_texture_name() const { return m_normal_texture_name; }
        int16_t sector_id() const { return m_sector_id; }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::sidedefs_t* _parent() const { return m__parent; }
    };

    class things_t : public kaitai::kstruct {

    public:

        things_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~things_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<thing_t>>> m_entries;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:
        std::vector<std::unique_ptr<thing_t>>* entries() const { return m_entries.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class linedefs_t : public kaitai::kstruct {

    public:

        linedefs_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~linedefs_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<linedef_t>>> m_entries;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:
        std::vector<std::unique_ptr<linedef_t>>* entries() const { return m_entries.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class index_entry_t : public kaitai::kstruct {

    public:

        index_entry_t(kaitai::kstream* p__io, doom_wad_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~index_entry_t();

    private:
        bool f_contents;
        std::unique_ptr<kaitai::kstruct> m_contents;
        bool n_contents;

    public:
        bool _is_null_contents() { contents(); return n_contents; };

    private:

    public:
        kaitai::kstruct* contents();

    private:
        int32_t m_offset;
        int32_t m_size;
        std::string m_name;
        doom_wad_t* m__root;
        doom_wad_t* m__parent;
        std::string m__raw_contents;
        std::unique_ptr<kaitai::kstream> m__io__raw_contents;

    public:
        int32_t offset() const { return m_offset; }
        int32_t size() const { return m_size; }
        std::string name() const { return m_name; }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t* _parent() const { return m__parent; }
        std::string _raw_contents() const { return m__raw_contents; }
        kaitai::kstream* _io__raw_contents() const { return m__io__raw_contents.get(); }
    };

    class sidedefs_t : public kaitai::kstruct {

    public:

        sidedefs_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~sidedefs_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<sidedef_t>>> m_entries;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:
        std::vector<std::unique_ptr<sidedef_t>>* entries() const { return m_entries.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

    class blockmap_t : public kaitai::kstruct {

    public:
        class blocklist_t;

        blockmap_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

    public:
        ~blockmap_t();

        class blocklist_t : public kaitai::kstruct {

        public:

            blocklist_t(kaitai::kstream* p__io, doom_wad_t::blockmap_t* p__parent = nullptr, doom_wad_t* p__root = nullptr);

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

        public:
            ~blocklist_t();

        private:
            bool f_linedefs;
            std::unique_ptr<std::vector<int16_t>> m_linedefs;

        public:

            /**
             * List of linedefs found in this block
             */
            std::vector<int16_t>* linedefs();

        private:
            uint16_t m_offset;
            doom_wad_t* m__root;
            doom_wad_t::blockmap_t* m__parent;

        public:

            /**
             * Offset to the list of linedefs
             */
            uint16_t offset() const { return m_offset; }
            doom_wad_t* _root() const { return m__root; }
            doom_wad_t::blockmap_t* _parent() const { return m__parent; }
        };

    private:
        int16_t m_origin_x;
        int16_t m_origin_y;
        int16_t m_num_cols;
        int16_t m_num_rows;
        std::unique_ptr<std::vector<std::unique_ptr<blocklist_t>>> m_linedefs_in_block;
        doom_wad_t* m__root;
        doom_wad_t::index_entry_t* m__parent;

    public:

        /**
         * Grid origin, X coord
         */
        int16_t origin_x() const { return m_origin_x; }

        /**
         * Grid origin, Y coord
         */
        int16_t origin_y() const { return m_origin_y; }

        /**
         * Number of columns
         */
        int16_t num_cols() const { return m_num_cols; }

        /**
         * Number of rows
         */
        int16_t num_rows() const { return m_num_rows; }

        /**
         * Lists of linedefs for every block
         */
        std::vector<std::unique_ptr<blocklist_t>>* linedefs_in_block() const { return m_linedefs_in_block.get(); }
        doom_wad_t* _root() const { return m__root; }
        doom_wad_t::index_entry_t* _parent() const { return m__parent; }
    };

private:
    bool f_index;
    std::unique_ptr<std::vector<std::unique_ptr<index_entry_t>>> m_index;

public:
    std::vector<std::unique_ptr<index_entry_t>>* index();

private:
    std::string m_magic;
    int32_t m_num_index_entries;
    int32_t m_index_offset;
    doom_wad_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::string magic() const { return m_magic; }

    /**
     * Number of entries in the lump index
     */
    int32_t num_index_entries() const { return m_num_index_entries; }

    /**
     * Offset to the start of the index
     */
    int32_t index_offset() const { return m_index_offset; }
    doom_wad_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

doom_wad.cpp

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

#include "doom_wad.h"

doom_wad_t::doom_wad_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_index = nullptr;
    f_index = false;
    _read();
}

void doom_wad_t::_read() {
    m_magic = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), std::string("ASCII"));
    m_num_index_entries = m__io->read_s4le();
    m_index_offset = m__io->read_s4le();
}

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

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

doom_wad_t::sectors_t::sectors_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void doom_wad_t::sectors_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<sector_t>>>(new std::vector<std::unique_ptr<sector_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<sector_t>(new sector_t(m__io, this, m__root))));
            i++;
        }
    }
}

doom_wad_t::sectors_t::~sectors_t() {
    _clean_up();
}

void doom_wad_t::sectors_t::_clean_up() {
}

doom_wad_t::vertex_t::vertex_t(kaitai::kstream* p__io, doom_wad_t::vertexes_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void doom_wad_t::vertex_t::_read() {
    m_x = m__io->read_s2le();
    m_y = m__io->read_s2le();
}

doom_wad_t::vertex_t::~vertex_t() {
    _clean_up();
}

void doom_wad_t::vertex_t::_clean_up() {
}

doom_wad_t::texture12_t::texture12_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_textures = nullptr;
    _read();
}

void doom_wad_t::texture12_t::_read() {
    m_num_textures = m__io->read_s4le();
    m_textures = std::unique_ptr<std::vector<std::unique_ptr<texture_index_t>>>(new std::vector<std::unique_ptr<texture_index_t>>());
    const int l_textures = num_textures();
    for (int i = 0; i < l_textures; i++) {
        m_textures->push_back(std::move(std::unique_ptr<texture_index_t>(new texture_index_t(m__io, this, m__root))));
    }
}

doom_wad_t::texture12_t::~texture12_t() {
    _clean_up();
}

void doom_wad_t::texture12_t::_clean_up() {
}

doom_wad_t::texture12_t::texture_index_t::texture_index_t(kaitai::kstream* p__io, doom_wad_t::texture12_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_body = nullptr;
    f_body = false;
    _read();
}

void doom_wad_t::texture12_t::texture_index_t::_read() {
    m_offset = m__io->read_s4le();
}

doom_wad_t::texture12_t::texture_index_t::~texture_index_t() {
    _clean_up();
}

void doom_wad_t::texture12_t::texture_index_t::_clean_up() {
    if (f_body) {
    }
}

doom_wad_t::texture12_t::texture_body_t* doom_wad_t::texture12_t::texture_index_t::body() {
    if (f_body)
        return m_body.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(offset());
    m_body = std::unique_ptr<texture_body_t>(new texture_body_t(m__io, this, m__root));
    m__io->seek(_pos);
    f_body = true;
    return m_body.get();
}

doom_wad_t::texture12_t::texture_body_t::texture_body_t(kaitai::kstream* p__io, doom_wad_t::texture12_t::texture_index_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_patches = nullptr;
    _read();
}

void doom_wad_t::texture12_t::texture_body_t::_read() {
    m_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 0), std::string("ASCII"));
    m_masked = m__io->read_u4le();
    m_width = m__io->read_u2le();
    m_height = m__io->read_u2le();
    m_column_directory = m__io->read_u4le();
    m_num_patches = m__io->read_u2le();
    m_patches = std::unique_ptr<std::vector<std::unique_ptr<patch_t>>>(new std::vector<std::unique_ptr<patch_t>>());
    const int l_patches = num_patches();
    for (int i = 0; i < l_patches; i++) {
        m_patches->push_back(std::move(std::unique_ptr<patch_t>(new patch_t(m__io, this, m__root))));
    }
}

doom_wad_t::texture12_t::texture_body_t::~texture_body_t() {
    _clean_up();
}

void doom_wad_t::texture12_t::texture_body_t::_clean_up() {
}

doom_wad_t::texture12_t::patch_t::patch_t(kaitai::kstream* p__io, doom_wad_t::texture12_t::texture_body_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void doom_wad_t::texture12_t::patch_t::_read() {
    m_origin_x = m__io->read_s2le();
    m_origin_y = m__io->read_s2le();
    m_patch_id = m__io->read_u2le();
    m_step_dir = m__io->read_u2le();
    m_colormap = m__io->read_u2le();
}

doom_wad_t::texture12_t::patch_t::~patch_t() {
    _clean_up();
}

void doom_wad_t::texture12_t::patch_t::_clean_up() {
}

doom_wad_t::linedef_t::linedef_t(kaitai::kstream* p__io, doom_wad_t::linedefs_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void doom_wad_t::linedef_t::_read() {
    m_vertex_start_idx = m__io->read_u2le();
    m_vertex_end_idx = m__io->read_u2le();
    m_flags = m__io->read_u2le();
    m_line_type = m__io->read_u2le();
    m_sector_tag = m__io->read_u2le();
    m_sidedef_right_idx = m__io->read_u2le();
    m_sidedef_left_idx = m__io->read_u2le();
}

doom_wad_t::linedef_t::~linedef_t() {
    _clean_up();
}

void doom_wad_t::linedef_t::_clean_up() {
}

doom_wad_t::pnames_t::pnames_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_names = nullptr;
    _read();
}

void doom_wad_t::pnames_t::_read() {
    m_num_patches = m__io->read_u4le();
    m_names = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    const int l_names = num_patches();
    for (int i = 0; i < l_names; i++) {
        m_names->push_back(std::move(kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 0), std::string("ASCII"))));
    }
}

doom_wad_t::pnames_t::~pnames_t() {
    _clean_up();
}

void doom_wad_t::pnames_t::_clean_up() {
}

doom_wad_t::thing_t::thing_t(kaitai::kstream* p__io, doom_wad_t::things_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void doom_wad_t::thing_t::_read() {
    m_x = m__io->read_s2le();
    m_y = m__io->read_s2le();
    m_angle = m__io->read_u2le();
    m_type = m__io->read_u2le();
    m_flags = m__io->read_u2le();
}

doom_wad_t::thing_t::~thing_t() {
    _clean_up();
}

void doom_wad_t::thing_t::_clean_up() {
}

doom_wad_t::sector_t::sector_t(kaitai::kstream* p__io, doom_wad_t::sectors_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void doom_wad_t::sector_t::_read() {
    m_floor_z = m__io->read_s2le();
    m_ceil_z = m__io->read_s2le();
    m_floor_flat = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ASCII"));
    m_ceil_flat = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ASCII"));
    m_light = m__io->read_s2le();
    m_special_type = static_cast<doom_wad_t::sector_t::special_sector_t>(m__io->read_u2le());
    m_tag = m__io->read_u2le();
}

doom_wad_t::sector_t::~sector_t() {
    _clean_up();
}

void doom_wad_t::sector_t::_clean_up() {
}

doom_wad_t::vertexes_t::vertexes_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void doom_wad_t::vertexes_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<vertex_t>>>(new std::vector<std::unique_ptr<vertex_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<vertex_t>(new vertex_t(m__io, this, m__root))));
            i++;
        }
    }
}

doom_wad_t::vertexes_t::~vertexes_t() {
    _clean_up();
}

void doom_wad_t::vertexes_t::_clean_up() {
}

doom_wad_t::sidedef_t::sidedef_t(kaitai::kstream* p__io, doom_wad_t::sidedefs_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void doom_wad_t::sidedef_t::_read() {
    m_offset_x = m__io->read_s2le();
    m_offset_y = m__io->read_s2le();
    m_upper_texture_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ASCII"));
    m_lower_texture_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ASCII"));
    m_normal_texture_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ASCII"));
    m_sector_id = m__io->read_s2le();
}

doom_wad_t::sidedef_t::~sidedef_t() {
    _clean_up();
}

void doom_wad_t::sidedef_t::_clean_up() {
}

doom_wad_t::things_t::things_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void doom_wad_t::things_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<thing_t>>>(new std::vector<std::unique_ptr<thing_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<thing_t>(new thing_t(m__io, this, m__root))));
            i++;
        }
    }
}

doom_wad_t::things_t::~things_t() {
    _clean_up();
}

void doom_wad_t::things_t::_clean_up() {
}

doom_wad_t::linedefs_t::linedefs_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void doom_wad_t::linedefs_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<linedef_t>>>(new std::vector<std::unique_ptr<linedef_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<linedef_t>(new linedef_t(m__io, this, m__root))));
            i++;
        }
    }
}

doom_wad_t::linedefs_t::~linedefs_t() {
    _clean_up();
}

void doom_wad_t::linedefs_t::_clean_up() {
}

doom_wad_t::index_entry_t::index_entry_t(kaitai::kstream* p__io, doom_wad_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_contents = nullptr;
    f_contents = false;
    _read();
}

void doom_wad_t::index_entry_t::_read() {
    m_offset = m__io->read_s4le();
    m_size = m__io->read_s4le();
    m_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 0), std::string("ASCII"));
}

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

void doom_wad_t::index_entry_t::_clean_up() {
    if (f_contents && !n_contents) {
    }
}

kaitai::kstruct* doom_wad_t::index_entry_t::contents() {
    if (f_contents)
        return m_contents.get();
    kaitai::kstream *io = _root()->_io();
    std::streampos _pos = io->pos();
    io->seek(offset());
    n_contents = true;
    {
        std::string on = name();
        if (on == std::string("SECTORS")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<sectors_t>(new sectors_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("TEXTURE1")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<texture12_t>(new texture12_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("VERTEXES")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<vertexes_t>(new vertexes_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("BLOCKMAP")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<blockmap_t>(new blockmap_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("PNAMES")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<pnames_t>(new pnames_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("TEXTURE2")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<texture12_t>(new texture12_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("THINGS")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<things_t>(new things_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("LINEDEFS")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<linedefs_t>(new linedefs_t(m__io__raw_contents.get(), this, m__root));
        }
        else if (on == std::string("SIDEDEFS")) {
            n_contents = false;
            m__raw_contents = io->read_bytes(size());
            m__io__raw_contents = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_contents));
            m_contents = std::unique_ptr<sidedefs_t>(new sidedefs_t(m__io__raw_contents.get(), this, m__root));
        }
        else {
            m__raw_contents = io->read_bytes(size());
        }
    }
    io->seek(_pos);
    f_contents = true;
    return m_contents.get();
}

doom_wad_t::sidedefs_t::sidedefs_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void doom_wad_t::sidedefs_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<sidedef_t>>>(new std::vector<std::unique_ptr<sidedef_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<sidedef_t>(new sidedef_t(m__io, this, m__root))));
            i++;
        }
    }
}

doom_wad_t::sidedefs_t::~sidedefs_t() {
    _clean_up();
}

void doom_wad_t::sidedefs_t::_clean_up() {
}

doom_wad_t::blockmap_t::blockmap_t(kaitai::kstream* p__io, doom_wad_t::index_entry_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_linedefs_in_block = nullptr;
    _read();
}

void doom_wad_t::blockmap_t::_read() {
    m_origin_x = m__io->read_s2le();
    m_origin_y = m__io->read_s2le();
    m_num_cols = m__io->read_s2le();
    m_num_rows = m__io->read_s2le();
    m_linedefs_in_block = std::unique_ptr<std::vector<std::unique_ptr<blocklist_t>>>(new std::vector<std::unique_ptr<blocklist_t>>());
    const int l_linedefs_in_block = (num_cols() * num_rows());
    for (int i = 0; i < l_linedefs_in_block; i++) {
        m_linedefs_in_block->push_back(std::move(std::unique_ptr<blocklist_t>(new blocklist_t(m__io, this, m__root))));
    }
}

doom_wad_t::blockmap_t::~blockmap_t() {
    _clean_up();
}

void doom_wad_t::blockmap_t::_clean_up() {
}

doom_wad_t::blockmap_t::blocklist_t::blocklist_t(kaitai::kstream* p__io, doom_wad_t::blockmap_t* p__parent, doom_wad_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_linedefs = nullptr;
    f_linedefs = false;
    _read();
}

void doom_wad_t::blockmap_t::blocklist_t::_read() {
    m_offset = m__io->read_u2le();
}

doom_wad_t::blockmap_t::blocklist_t::~blocklist_t() {
    _clean_up();
}

void doom_wad_t::blockmap_t::blocklist_t::_clean_up() {
    if (f_linedefs) {
    }
}

std::vector<int16_t>* doom_wad_t::blockmap_t::blocklist_t::linedefs() {
    if (f_linedefs)
        return m_linedefs.get();
    std::streampos _pos = m__io->pos();
    m__io->seek((offset() * 2));
    m_linedefs = std::unique_ptr<std::vector<int16_t>>(new std::vector<int16_t>());
    {
        int i = 0;
        int16_t _;
        do {
            _ = m__io->read_s2le();
            m_linedefs->push_back(_);
            i++;
        } while (!(_ == -1));
    }
    m__io->seek(_pos);
    f_linedefs = true;
    return m_linedefs.get();
}

std::vector<std::unique_ptr<doom_wad_t::index_entry_t>>* doom_wad_t::index() {
    if (f_index)
        return m_index.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(index_offset());
    m_index = std::unique_ptr<std::vector<std::unique_ptr<index_entry_t>>>(new std::vector<std::unique_ptr<index_entry_t>>());
    const int l_index = num_index_entries();
    for (int i = 0; i < l_index; i++) {
        m_index->push_back(std::move(std::unique_ptr<index_entry_t>(new index_entry_t(m__io, this, m__root))));
    }
    m__io->seek(_pos);
    f_index = true;
    return m_index.get();
}