ZIP archive file: C++11/STL parsing library

ZIP is a popular archive file format, introduced in 1989 by Phil Katz and originally implemented in PKZIP utility by PKWARE.

Thanks to solid support of it in most desktop environments and operating systems, and algorithms / specs availability in public domain, it quickly became tool of choice for implementing file containers.

For example, Java .jar files, OpenDocument, Office Open XML, EPUB files are actually ZIP archives.

File extension

zip

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of ZIP archive file 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.zip", 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:
    zip_t data(&ks);
    

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

data.sections() // => get sections

C++11/STL source code to parse ZIP archive file

zip.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 "dos_datetime.h"
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class dos_datetime_t;

/**
 * ZIP is a popular archive file format, introduced in 1989 by Phil Katz
 * and originally implemented in PKZIP utility by PKWARE.
 * 
 * Thanks to solid support of it in most desktop environments and
 * operating systems, and algorithms / specs availability in public
 * domain, it quickly became tool of choice for implementing file
 * containers.
 * 
 * For example, Java .jar files, OpenDocument, Office Open XML, EPUB files
 * are actually ZIP archives.
 * \sa https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT Source
 * \sa https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html Source
 */

class zip_t : public kaitai::kstruct {

public:
    class local_file_t;
    class data_descriptor_t;
    class extra_field_t;
    class central_dir_entry_t;
    class pk_section_t;
    class extras_t;
    class local_file_header_t;
    class end_of_central_dir_t;

    enum compression_t {
        COMPRESSION_NONE = 0,
        COMPRESSION_SHRUNK = 1,
        COMPRESSION_REDUCED_1 = 2,
        COMPRESSION_REDUCED_2 = 3,
        COMPRESSION_REDUCED_3 = 4,
        COMPRESSION_REDUCED_4 = 5,
        COMPRESSION_IMPLODED = 6,
        COMPRESSION_DEFLATED = 8,
        COMPRESSION_ENHANCED_DEFLATED = 9,
        COMPRESSION_PKWARE_DCL_IMPLODED = 10,
        COMPRESSION_BZIP2 = 12,
        COMPRESSION_LZMA = 14,
        COMPRESSION_IBM_TERSE = 18,
        COMPRESSION_IBM_LZ77_Z = 19,
        COMPRESSION_ZSTANDARD = 93,
        COMPRESSION_MP3 = 94,
        COMPRESSION_XZ = 95,
        COMPRESSION_JPEG = 96,
        COMPRESSION_WAVPACK = 97,
        COMPRESSION_PPMD = 98,
        COMPRESSION_AEX_ENCRYPTION_MARKER = 99
    };

    enum extra_codes_t {
        EXTRA_CODES_ZIP64 = 1,
        EXTRA_CODES_AV_INFO = 7,
        EXTRA_CODES_OS2 = 9,
        EXTRA_CODES_NTFS = 10,
        EXTRA_CODES_OPENVMS = 12,
        EXTRA_CODES_PKWARE_UNIX = 13,
        EXTRA_CODES_FILE_STREAM_AND_FORK_DESCRIPTORS = 14,
        EXTRA_CODES_PATCH_DESCRIPTOR = 15,
        EXTRA_CODES_PKCS7 = 20,
        EXTRA_CODES_X509_CERT_ID_AND_SIGNATURE_FOR_FILE = 21,
        EXTRA_CODES_X509_CERT_ID_FOR_CENTRAL_DIR = 22,
        EXTRA_CODES_STRONG_ENCRYPTION_HEADER = 23,
        EXTRA_CODES_RECORD_MANAGEMENT_CONTROLS = 24,
        EXTRA_CODES_PKCS7_ENC_RECIP_CERT_LIST = 25,
        EXTRA_CODES_IBM_S390_UNCOMP = 101,
        EXTRA_CODES_IBM_S390_COMP = 102,
        EXTRA_CODES_POSZIP_4690 = 18064,
        EXTRA_CODES_EXTENDED_TIMESTAMP = 21589,
        EXTRA_CODES_BEOS = 25922,
        EXTRA_CODES_ASI_UNIX = 30062,
        EXTRA_CODES_INFOZIP_UNIX = 30805,
        EXTRA_CODES_INFOZIP_UNIX_VAR_SIZE = 30837,
        EXTRA_CODES_AEX_ENCRYPTION = 39169,
        EXTRA_CODES_APACHE_COMMONS_COMPRESS = 41246,
        EXTRA_CODES_MICROSOFT_OPEN_PACKAGING_GROWTH_HINT = 41504,
        EXTRA_CODES_SMS_QDOS = 64842
    };

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

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

public:
    ~zip_t();

    class local_file_t : public kaitai::kstruct {

    public:

        local_file_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

    public:
        ~local_file_t();

    private:
        std::unique_ptr<local_file_header_t> m_header;
        std::string m_body;
        zip_t* m__root;
        zip_t::pk_section_t* m__parent;

    public:
        local_file_header_t* header() const { return m_header.get(); }
        std::string body() const { return m_body; }
        zip_t* _root() const { return m__root; }
        zip_t::pk_section_t* _parent() const { return m__parent; }
    };

    class data_descriptor_t : public kaitai::kstruct {

    public:

        data_descriptor_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

    public:
        ~data_descriptor_t();

    private:
        uint32_t m_crc32;
        uint32_t m_len_body_compressed;
        uint32_t m_len_body_uncompressed;
        zip_t* m__root;
        zip_t::pk_section_t* m__parent;

    public:
        uint32_t crc32() const { return m_crc32; }
        uint32_t len_body_compressed() const { return m_len_body_compressed; }
        uint32_t len_body_uncompressed() const { return m_len_body_uncompressed; }
        zip_t* _root() const { return m__root; }
        zip_t::pk_section_t* _parent() const { return m__parent; }
    };

    class extra_field_t : public kaitai::kstruct {

    public:
        class ntfs_t;
        class extended_timestamp_t;
        class infozip_unix_var_size_t;

        extra_field_t(kaitai::kstream* p__io, zip_t::extras_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

    public:
        ~extra_field_t();

        /**
         * \sa https://github.com/LuaDist/zip/blob/b710806/proginfo/extrafld.txt#L191 Source
         */

        class ntfs_t : public kaitai::kstruct {

        public:
            class attribute_t;
            class attribute_1_t;

            ntfs_t(kaitai::kstream* p__io, zip_t::extra_field_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

        public:
            ~ntfs_t();

            class attribute_t : public kaitai::kstruct {

            public:

                attribute_t(kaitai::kstream* p__io, zip_t::extra_field_t::ntfs_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

            public:
                ~attribute_t();

            private:
                uint16_t m_tag;
                uint16_t m_len_body;
                std::unique_ptr<attribute_1_t> m_body;
                bool n_body;

            public:
                bool _is_null_body() { body(); return n_body; };

            private:
                zip_t* m__root;
                zip_t::extra_field_t::ntfs_t* m__parent;
                std::string m__raw_body;
                std::unique_ptr<kaitai::kstream> m__io__raw_body;

            public:
                uint16_t tag() const { return m_tag; }
                uint16_t len_body() const { return m_len_body; }
                attribute_1_t* body() const { return m_body.get(); }
                zip_t* _root() const { return m__root; }
                zip_t::extra_field_t::ntfs_t* _parent() const { return m__parent; }
                std::string _raw_body() const { return m__raw_body; }
                kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); }
            };

            class attribute_1_t : public kaitai::kstruct {

            public:

                attribute_1_t(kaitai::kstream* p__io, zip_t::extra_field_t::ntfs_t::attribute_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

            public:
                ~attribute_1_t();

            private:
                uint64_t m_last_mod_time;
                uint64_t m_last_access_time;
                uint64_t m_creation_time;
                zip_t* m__root;
                zip_t::extra_field_t::ntfs_t::attribute_t* m__parent;

            public:
                uint64_t last_mod_time() const { return m_last_mod_time; }
                uint64_t last_access_time() const { return m_last_access_time; }
                uint64_t creation_time() const { return m_creation_time; }
                zip_t* _root() const { return m__root; }
                zip_t::extra_field_t::ntfs_t::attribute_t* _parent() const { return m__parent; }
            };

        private:
            uint32_t m_reserved;
            std::unique_ptr<std::vector<std::unique_ptr<attribute_t>>> m_attributes;
            zip_t* m__root;
            zip_t::extra_field_t* m__parent;

        public:
            uint32_t reserved() const { return m_reserved; }
            std::vector<std::unique_ptr<attribute_t>>* attributes() const { return m_attributes.get(); }
            zip_t* _root() const { return m__root; }
            zip_t::extra_field_t* _parent() const { return m__parent; }
        };

        /**
         * \sa https://github.com/LuaDist/zip/blob/b710806/proginfo/extrafld.txt#L817 Source
         */

        class extended_timestamp_t : public kaitai::kstruct {

        public:
            class info_flags_t;

            extended_timestamp_t(kaitai::kstream* p__io, zip_t::extra_field_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

        public:
            ~extended_timestamp_t();

            class info_flags_t : public kaitai::kstruct {

            public:

                info_flags_t(kaitai::kstream* p__io, zip_t::extra_field_t::extended_timestamp_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

            public:
                ~info_flags_t();

            private:
                bool m_has_mod_time;
                bool m_has_access_time;
                bool m_has_create_time;
                uint64_t m_reserved;
                zip_t* m__root;
                zip_t::extra_field_t::extended_timestamp_t* m__parent;

            public:
                bool has_mod_time() const { return m_has_mod_time; }
                bool has_access_time() const { return m_has_access_time; }
                bool has_create_time() const { return m_has_create_time; }
                uint64_t reserved() const { return m_reserved; }
                zip_t* _root() const { return m__root; }
                zip_t::extra_field_t::extended_timestamp_t* _parent() const { return m__parent; }
            };

        private:
            std::unique_ptr<info_flags_t> m_flags;
            uint32_t m_mod_time;
            bool n_mod_time;

        public:
            bool _is_null_mod_time() { mod_time(); return n_mod_time; };

        private:
            uint32_t m_access_time;
            bool n_access_time;

        public:
            bool _is_null_access_time() { access_time(); return n_access_time; };

        private:
            uint32_t m_create_time;
            bool n_create_time;

        public:
            bool _is_null_create_time() { create_time(); return n_create_time; };

        private:
            zip_t* m__root;
            zip_t::extra_field_t* m__parent;
            std::string m__raw_flags;
            std::unique_ptr<kaitai::kstream> m__io__raw_flags;

        public:
            info_flags_t* flags() const { return m_flags.get(); }

            /**
             * Unix timestamp
             */
            uint32_t mod_time() const { return m_mod_time; }

            /**
             * Unix timestamp
             */
            uint32_t access_time() const { return m_access_time; }

            /**
             * Unix timestamp
             */
            uint32_t create_time() const { return m_create_time; }
            zip_t* _root() const { return m__root; }
            zip_t::extra_field_t* _parent() const { return m__parent; }
            std::string _raw_flags() const { return m__raw_flags; }
            kaitai::kstream* _io__raw_flags() const { return m__io__raw_flags.get(); }
        };

        /**
         * \sa https://github.com/LuaDist/zip/blob/b710806/proginfo/extrafld.txt#L1339 Source
         */

        class infozip_unix_var_size_t : public kaitai::kstruct {

        public:

            infozip_unix_var_size_t(kaitai::kstream* p__io, zip_t::extra_field_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

        public:
            ~infozip_unix_var_size_t();

        private:
            uint8_t m_version;
            uint8_t m_len_uid;
            std::string m_uid;
            uint8_t m_len_gid;
            std::string m_gid;
            zip_t* m__root;
            zip_t::extra_field_t* m__parent;

        public:

            /**
             * Version of this extra field, currently 1
             */
            uint8_t version() const { return m_version; }

            /**
             * Size of UID field
             */
            uint8_t len_uid() const { return m_len_uid; }

            /**
             * UID (User ID) for a file
             */
            std::string uid() const { return m_uid; }

            /**
             * Size of GID field
             */
            uint8_t len_gid() const { return m_len_gid; }

            /**
             * GID (Group ID) for a file
             */
            std::string gid() const { return m_gid; }
            zip_t* _root() const { return m__root; }
            zip_t::extra_field_t* _parent() const { return m__parent; }
        };

    private:
        extra_codes_t m_code;
        uint16_t m_len_body;
        std::unique_ptr<kaitai::kstruct> m_body;
        bool n_body;

    public:
        bool _is_null_body() { body(); return n_body; };

    private:
        zip_t* m__root;
        zip_t::extras_t* m__parent;
        std::string m__raw_body;
        std::unique_ptr<kaitai::kstream> m__io__raw_body;

    public:
        extra_codes_t code() const { return m_code; }
        uint16_t len_body() const { return m_len_body; }
        kaitai::kstruct* body() const { return m_body.get(); }
        zip_t* _root() const { return m__root; }
        zip_t::extras_t* _parent() const { return m__parent; }
        std::string _raw_body() const { return m__raw_body; }
        kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); }
    };

    /**
     * \sa https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT - 4.3.12
     */

    class central_dir_entry_t : public kaitai::kstruct {

    public:

        central_dir_entry_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

    public:
        ~central_dir_entry_t();

    private:
        bool f_local_header;
        std::unique_ptr<pk_section_t> m_local_header;

    public:
        pk_section_t* local_header();

    private:
        uint16_t m_version_made_by;
        uint16_t m_version_needed_to_extract;
        uint16_t m_flags;
        compression_t m_compression_method;
        std::unique_ptr<dos_datetime_t> m_file_mod_time;
        uint32_t m_crc32;
        uint32_t m_len_body_compressed;
        uint32_t m_len_body_uncompressed;
        uint16_t m_len_file_name;
        uint16_t m_len_extra;
        uint16_t m_len_comment;
        uint16_t m_disk_number_start;
        uint16_t m_int_file_attr;
        uint32_t m_ext_file_attr;
        int32_t m_ofs_local_header;
        std::string m_file_name;
        std::unique_ptr<extras_t> m_extra;
        std::string m_comment;
        zip_t* m__root;
        zip_t::pk_section_t* m__parent;
        std::string m__raw_file_mod_time;
        std::unique_ptr<kaitai::kstream> m__io__raw_file_mod_time;
        std::string m__raw_extra;
        std::unique_ptr<kaitai::kstream> m__io__raw_extra;

    public:
        uint16_t version_made_by() const { return m_version_made_by; }
        uint16_t version_needed_to_extract() const { return m_version_needed_to_extract; }
        uint16_t flags() const { return m_flags; }
        compression_t compression_method() const { return m_compression_method; }
        dos_datetime_t* file_mod_time() const { return m_file_mod_time.get(); }
        uint32_t crc32() const { return m_crc32; }
        uint32_t len_body_compressed() const { return m_len_body_compressed; }
        uint32_t len_body_uncompressed() const { return m_len_body_uncompressed; }
        uint16_t len_file_name() const { return m_len_file_name; }
        uint16_t len_extra() const { return m_len_extra; }
        uint16_t len_comment() const { return m_len_comment; }
        uint16_t disk_number_start() const { return m_disk_number_start; }
        uint16_t int_file_attr() const { return m_int_file_attr; }
        uint32_t ext_file_attr() const { return m_ext_file_attr; }
        int32_t ofs_local_header() const { return m_ofs_local_header; }
        std::string file_name() const { return m_file_name; }
        extras_t* extra() const { return m_extra.get(); }
        std::string comment() const { return m_comment; }
        zip_t* _root() const { return m__root; }
        zip_t::pk_section_t* _parent() const { return m__parent; }
        std::string _raw_file_mod_time() const { return m__raw_file_mod_time; }
        kaitai::kstream* _io__raw_file_mod_time() const { return m__io__raw_file_mod_time.get(); }
        std::string _raw_extra() const { return m__raw_extra; }
        kaitai::kstream* _io__raw_extra() const { return m__io__raw_extra.get(); }
    };

    class pk_section_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~pk_section_t();

    private:
        std::string m_magic;
        uint16_t m_section_type;
        std::unique_ptr<kaitai::kstruct> m_body;
        bool n_body;

    public:
        bool _is_null_body() { body(); return n_body; };

    private:
        zip_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint16_t section_type() const { return m_section_type; }
        kaitai::kstruct* body() const { return m_body.get(); }
        zip_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class extras_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~extras_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<extra_field_t>>> m_entries;
        zip_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        std::vector<std::unique_ptr<extra_field_t>>* entries() const { return m_entries.get(); }
        zip_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class local_file_header_t : public kaitai::kstruct {

    public:
        class gp_flags_t;

        local_file_header_t(kaitai::kstream* p__io, zip_t::local_file_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

    public:
        ~local_file_header_t();

        /**
         * \sa https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT - 4.4.4
         * \sa https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html Local file headers
         */

        class gp_flags_t : public kaitai::kstruct {

        public:

            enum deflate_mode_t {
                DEFLATE_MODE_NORMAL = 0,
                DEFLATE_MODE_MAXIMUM = 1,
                DEFLATE_MODE_FAST = 2,
                DEFLATE_MODE_SUPER_FAST = 3
            };

            gp_flags_t(kaitai::kstream* p__io, zip_t::local_file_header_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

        public:
            ~gp_flags_t();

        private:
            bool f_deflated_mode;
            deflate_mode_t m_deflated_mode;
            bool n_deflated_mode;

        public:
            bool _is_null_deflated_mode() { deflated_mode(); return n_deflated_mode; };

        private:

        public:
            deflate_mode_t deflated_mode();

        private:
            bool f_imploded_dict_byte_size;
            int32_t m_imploded_dict_byte_size;
            bool n_imploded_dict_byte_size;

        public:
            bool _is_null_imploded_dict_byte_size() { imploded_dict_byte_size(); return n_imploded_dict_byte_size; };

        private:

        public:

            /**
             * 8KiB or 4KiB in bytes
             */
            int32_t imploded_dict_byte_size();

        private:
            bool f_imploded_num_sf_trees;
            int8_t m_imploded_num_sf_trees;
            bool n_imploded_num_sf_trees;

        public:
            bool _is_null_imploded_num_sf_trees() { imploded_num_sf_trees(); return n_imploded_num_sf_trees; };

        private:

        public:
            int8_t imploded_num_sf_trees();

        private:
            bool f_lzma_has_eos_marker;
            bool m_lzma_has_eos_marker;
            bool n_lzma_has_eos_marker;

        public:
            bool _is_null_lzma_has_eos_marker() { lzma_has_eos_marker(); return n_lzma_has_eos_marker; };

        private:

        public:
            bool lzma_has_eos_marker();

        private:
            bool m_file_encrypted;
            uint64_t m_comp_options_raw;
            bool m_has_data_descriptor;
            bool m_reserved_1;
            bool m_comp_patched_data;
            bool m_strong_encrypt;
            uint64_t m_reserved_2;
            bool m_lang_encoding;
            bool m_reserved_3;
            bool m_mask_header_values;
            uint64_t m_reserved_4;
            zip_t* m__root;
            zip_t::local_file_header_t* m__parent;

        public:
            bool file_encrypted() const { return m_file_encrypted; }

            /**
             * internal; access derived value instances instead
             */
            uint64_t comp_options_raw() const { return m_comp_options_raw; }
            bool has_data_descriptor() const { return m_has_data_descriptor; }
            bool reserved_1() const { return m_reserved_1; }
            bool comp_patched_data() const { return m_comp_patched_data; }
            bool strong_encrypt() const { return m_strong_encrypt; }
            uint64_t reserved_2() const { return m_reserved_2; }
            bool lang_encoding() const { return m_lang_encoding; }
            bool reserved_3() const { return m_reserved_3; }
            bool mask_header_values() const { return m_mask_header_values; }
            uint64_t reserved_4() const { return m_reserved_4; }
            zip_t* _root() const { return m__root; }
            zip_t::local_file_header_t* _parent() const { return m__parent; }
        };

    private:
        uint16_t m_version;
        std::unique_ptr<gp_flags_t> m_flags;
        compression_t m_compression_method;
        std::unique_ptr<dos_datetime_t> m_file_mod_time;
        uint32_t m_crc32;
        uint32_t m_len_body_compressed;
        uint32_t m_len_body_uncompressed;
        uint16_t m_len_file_name;
        uint16_t m_len_extra;
        std::string m_file_name;
        std::unique_ptr<extras_t> m_extra;
        zip_t* m__root;
        zip_t::local_file_t* m__parent;
        std::string m__raw_flags;
        std::unique_ptr<kaitai::kstream> m__io__raw_flags;
        std::string m__raw_file_mod_time;
        std::unique_ptr<kaitai::kstream> m__io__raw_file_mod_time;
        std::string m__raw_extra;
        std::unique_ptr<kaitai::kstream> m__io__raw_extra;

    public:
        uint16_t version() const { return m_version; }
        gp_flags_t* flags() const { return m_flags.get(); }
        compression_t compression_method() const { return m_compression_method; }
        dos_datetime_t* file_mod_time() const { return m_file_mod_time.get(); }
        uint32_t crc32() const { return m_crc32; }
        uint32_t len_body_compressed() const { return m_len_body_compressed; }
        uint32_t len_body_uncompressed() const { return m_len_body_uncompressed; }
        uint16_t len_file_name() const { return m_len_file_name; }
        uint16_t len_extra() const { return m_len_extra; }
        std::string file_name() const { return m_file_name; }
        extras_t* extra() const { return m_extra.get(); }
        zip_t* _root() const { return m__root; }
        zip_t::local_file_t* _parent() const { return m__parent; }
        std::string _raw_flags() const { return m__raw_flags; }
        kaitai::kstream* _io__raw_flags() const { return m__io__raw_flags.get(); }
        std::string _raw_file_mod_time() const { return m__raw_file_mod_time; }
        kaitai::kstream* _io__raw_file_mod_time() const { return m__io__raw_file_mod_time.get(); }
        std::string _raw_extra() const { return m__raw_extra; }
        kaitai::kstream* _io__raw_extra() const { return m__io__raw_extra.get(); }
    };

    class end_of_central_dir_t : public kaitai::kstruct {

    public:

        end_of_central_dir_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent = nullptr, zip_t* p__root = nullptr);

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

    public:
        ~end_of_central_dir_t();

    private:
        uint16_t m_disk_of_end_of_central_dir;
        uint16_t m_disk_of_central_dir;
        uint16_t m_num_central_dir_entries_on_disk;
        uint16_t m_num_central_dir_entries_total;
        uint32_t m_len_central_dir;
        uint32_t m_ofs_central_dir;
        uint16_t m_len_comment;
        std::string m_comment;
        zip_t* m__root;
        zip_t::pk_section_t* m__parent;

    public:
        uint16_t disk_of_end_of_central_dir() const { return m_disk_of_end_of_central_dir; }
        uint16_t disk_of_central_dir() const { return m_disk_of_central_dir; }
        uint16_t num_central_dir_entries_on_disk() const { return m_num_central_dir_entries_on_disk; }
        uint16_t num_central_dir_entries_total() const { return m_num_central_dir_entries_total; }
        uint32_t len_central_dir() const { return m_len_central_dir; }
        uint32_t ofs_central_dir() const { return m_ofs_central_dir; }
        uint16_t len_comment() const { return m_len_comment; }
        std::string comment() const { return m_comment; }
        zip_t* _root() const { return m__root; }
        zip_t::pk_section_t* _parent() const { return m__parent; }
    };

private:
    std::unique_ptr<std::vector<std::unique_ptr<pk_section_t>>> m_sections;
    zip_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::vector<std::unique_ptr<pk_section_t>>* sections() const { return m_sections.get(); }
    zip_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

zip.cpp

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

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

zip_t::zip_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_sections = nullptr;
    _read();
}

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

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

void zip_t::_clean_up() {
}

zip_t::local_file_t::local_file_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_header = nullptr;
    _read();
}

void zip_t::local_file_t::_read() {
    m_header = std::unique_ptr<local_file_header_t>(new local_file_header_t(m__io, this, m__root));
    m_body = m__io->read_bytes(header()->len_body_compressed());
}

zip_t::local_file_t::~local_file_t() {
    _clean_up();
}

void zip_t::local_file_t::_clean_up() {
}

zip_t::data_descriptor_t::data_descriptor_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void zip_t::data_descriptor_t::_read() {
    m_crc32 = m__io->read_u4le();
    m_len_body_compressed = m__io->read_u4le();
    m_len_body_uncompressed = m__io->read_u4le();
}

zip_t::data_descriptor_t::~data_descriptor_t() {
    _clean_up();
}

void zip_t::data_descriptor_t::_clean_up() {
}

zip_t::extra_field_t::extra_field_t(kaitai::kstream* p__io, zip_t::extras_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_body = nullptr;
    _read();
}

void zip_t::extra_field_t::_read() {
    m_code = static_cast<zip_t::extra_codes_t>(m__io->read_u2le());
    m_len_body = m__io->read_u2le();
    n_body = true;
    switch (code()) {
    case zip_t::EXTRA_CODES_NTFS: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<ntfs_t>(new ntfs_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case zip_t::EXTRA_CODES_EXTENDED_TIMESTAMP: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<extended_timestamp_t>(new extended_timestamp_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    case zip_t::EXTRA_CODES_INFOZIP_UNIX_VAR_SIZE: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<infozip_unix_var_size_t>(new infozip_unix_var_size_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    default: {
        m__raw_body = m__io->read_bytes(len_body());
        break;
    }
    }
}

zip_t::extra_field_t::~extra_field_t() {
    _clean_up();
}

void zip_t::extra_field_t::_clean_up() {
    if (!n_body) {
    }
}

zip_t::extra_field_t::ntfs_t::ntfs_t(kaitai::kstream* p__io, zip_t::extra_field_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_attributes = nullptr;
    _read();
}

void zip_t::extra_field_t::ntfs_t::_read() {
    m_reserved = m__io->read_u4le();
    m_attributes = std::unique_ptr<std::vector<std::unique_ptr<attribute_t>>>(new std::vector<std::unique_ptr<attribute_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_attributes->push_back(std::move(std::unique_ptr<attribute_t>(new attribute_t(m__io, this, m__root))));
            i++;
        }
    }
}

zip_t::extra_field_t::ntfs_t::~ntfs_t() {
    _clean_up();
}

void zip_t::extra_field_t::ntfs_t::_clean_up() {
}

zip_t::extra_field_t::ntfs_t::attribute_t::attribute_t(kaitai::kstream* p__io, zip_t::extra_field_t::ntfs_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_body = nullptr;
    _read();
}

void zip_t::extra_field_t::ntfs_t::attribute_t::_read() {
    m_tag = m__io->read_u2le();
    m_len_body = m__io->read_u2le();
    n_body = true;
    switch (tag()) {
    case 1: {
        n_body = false;
        m__raw_body = m__io->read_bytes(len_body());
        m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
        m_body = std::unique_ptr<attribute_1_t>(new attribute_1_t(m__io__raw_body.get(), this, m__root));
        break;
    }
    default: {
        m__raw_body = m__io->read_bytes(len_body());
        break;
    }
    }
}

zip_t::extra_field_t::ntfs_t::attribute_t::~attribute_t() {
    _clean_up();
}

void zip_t::extra_field_t::ntfs_t::attribute_t::_clean_up() {
    if (!n_body) {
    }
}

zip_t::extra_field_t::ntfs_t::attribute_1_t::attribute_1_t(kaitai::kstream* p__io, zip_t::extra_field_t::ntfs_t::attribute_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void zip_t::extra_field_t::ntfs_t::attribute_1_t::_read() {
    m_last_mod_time = m__io->read_u8le();
    m_last_access_time = m__io->read_u8le();
    m_creation_time = m__io->read_u8le();
}

zip_t::extra_field_t::ntfs_t::attribute_1_t::~attribute_1_t() {
    _clean_up();
}

void zip_t::extra_field_t::ntfs_t::attribute_1_t::_clean_up() {
}

zip_t::extra_field_t::extended_timestamp_t::extended_timestamp_t(kaitai::kstream* p__io, zip_t::extra_field_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = nullptr;
    m__io__raw_flags = nullptr;
    _read();
}

void zip_t::extra_field_t::extended_timestamp_t::_read() {
    m__raw_flags = m__io->read_bytes(1);
    m__io__raw_flags = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_flags));
    m_flags = std::unique_ptr<info_flags_t>(new info_flags_t(m__io__raw_flags.get(), this, m__root));
    n_mod_time = true;
    if (flags()->has_mod_time()) {
        n_mod_time = false;
        m_mod_time = m__io->read_u4le();
    }
    n_access_time = true;
    if (flags()->has_access_time()) {
        n_access_time = false;
        m_access_time = m__io->read_u4le();
    }
    n_create_time = true;
    if (flags()->has_create_time()) {
        n_create_time = false;
        m_create_time = m__io->read_u4le();
    }
}

zip_t::extra_field_t::extended_timestamp_t::~extended_timestamp_t() {
    _clean_up();
}

void zip_t::extra_field_t::extended_timestamp_t::_clean_up() {
    if (!n_mod_time) {
    }
    if (!n_access_time) {
    }
    if (!n_create_time) {
    }
}

zip_t::extra_field_t::extended_timestamp_t::info_flags_t::info_flags_t(kaitai::kstream* p__io, zip_t::extra_field_t::extended_timestamp_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void zip_t::extra_field_t::extended_timestamp_t::info_flags_t::_read() {
    m_has_mod_time = m__io->read_bits_int_le(1);
    m_has_access_time = m__io->read_bits_int_le(1);
    m_has_create_time = m__io->read_bits_int_le(1);
    m_reserved = m__io->read_bits_int_le(5);
}

zip_t::extra_field_t::extended_timestamp_t::info_flags_t::~info_flags_t() {
    _clean_up();
}

void zip_t::extra_field_t::extended_timestamp_t::info_flags_t::_clean_up() {
}

zip_t::extra_field_t::infozip_unix_var_size_t::infozip_unix_var_size_t(kaitai::kstream* p__io, zip_t::extra_field_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void zip_t::extra_field_t::infozip_unix_var_size_t::_read() {
    m_version = m__io->read_u1();
    m_len_uid = m__io->read_u1();
    m_uid = m__io->read_bytes(len_uid());
    m_len_gid = m__io->read_u1();
    m_gid = m__io->read_bytes(len_gid());
}

zip_t::extra_field_t::infozip_unix_var_size_t::~infozip_unix_var_size_t() {
    _clean_up();
}

void zip_t::extra_field_t::infozip_unix_var_size_t::_clean_up() {
}

zip_t::central_dir_entry_t::central_dir_entry_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_file_mod_time = nullptr;
    m__io__raw_file_mod_time = nullptr;
    m_extra = nullptr;
    m__io__raw_extra = nullptr;
    m_local_header = nullptr;
    f_local_header = false;
    _read();
}

void zip_t::central_dir_entry_t::_read() {
    m_version_made_by = m__io->read_u2le();
    m_version_needed_to_extract = m__io->read_u2le();
    m_flags = m__io->read_u2le();
    m_compression_method = static_cast<zip_t::compression_t>(m__io->read_u2le());
    m__raw_file_mod_time = m__io->read_bytes(4);
    m__io__raw_file_mod_time = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_file_mod_time));
    m_file_mod_time = std::unique_ptr<dos_datetime_t>(new dos_datetime_t(m__io__raw_file_mod_time.get()));
    m_crc32 = m__io->read_u4le();
    m_len_body_compressed = m__io->read_u4le();
    m_len_body_uncompressed = m__io->read_u4le();
    m_len_file_name = m__io->read_u2le();
    m_len_extra = m__io->read_u2le();
    m_len_comment = m__io->read_u2le();
    m_disk_number_start = m__io->read_u2le();
    m_int_file_attr = m__io->read_u2le();
    m_ext_file_attr = m__io->read_u4le();
    m_ofs_local_header = m__io->read_s4le();
    m_file_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(len_file_name()), std::string("UTF-8"));
    m__raw_extra = m__io->read_bytes(len_extra());
    m__io__raw_extra = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_extra));
    m_extra = std::unique_ptr<extras_t>(new extras_t(m__io__raw_extra.get(), this, m__root));
    m_comment = kaitai::kstream::bytes_to_str(m__io->read_bytes(len_comment()), std::string("UTF-8"));
}

zip_t::central_dir_entry_t::~central_dir_entry_t() {
    _clean_up();
}

void zip_t::central_dir_entry_t::_clean_up() {
    if (f_local_header) {
    }
}

zip_t::pk_section_t* zip_t::central_dir_entry_t::local_header() {
    if (f_local_header)
        return m_local_header.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(ofs_local_header());
    m_local_header = std::unique_ptr<pk_section_t>(new pk_section_t(m__io, this, m__root));
    m__io->seek(_pos);
    f_local_header = true;
    return m_local_header.get();
}

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

void zip_t::pk_section_t::_read() {
    m_magic = m__io->read_bytes(2);
    if (!(magic() == std::string("\x50\x4B", 2))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x50\x4B", 2), magic(), _io(), std::string("/types/pk_section/seq/0"));
    }
    m_section_type = m__io->read_u2le();
    n_body = true;
    switch (section_type()) {
    case 513: {
        n_body = false;
        m_body = std::unique_ptr<central_dir_entry_t>(new central_dir_entry_t(m__io, this, m__root));
        break;
    }
    case 1027: {
        n_body = false;
        m_body = std::unique_ptr<local_file_t>(new local_file_t(m__io, this, m__root));
        break;
    }
    case 1541: {
        n_body = false;
        m_body = std::unique_ptr<end_of_central_dir_t>(new end_of_central_dir_t(m__io, this, m__root));
        break;
    }
    case 2055: {
        n_body = false;
        m_body = std::unique_ptr<data_descriptor_t>(new data_descriptor_t(m__io, this, m__root));
        break;
    }
    }
}

zip_t::pk_section_t::~pk_section_t() {
    _clean_up();
}

void zip_t::pk_section_t::_clean_up() {
    if (!n_body) {
    }
}

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

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

zip_t::extras_t::~extras_t() {
    _clean_up();
}

void zip_t::extras_t::_clean_up() {
}

zip_t::local_file_header_t::local_file_header_t(kaitai::kstream* p__io, zip_t::local_file_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = nullptr;
    m__io__raw_flags = nullptr;
    m_file_mod_time = nullptr;
    m__io__raw_file_mod_time = nullptr;
    m_extra = nullptr;
    m__io__raw_extra = nullptr;
    _read();
}

void zip_t::local_file_header_t::_read() {
    m_version = m__io->read_u2le();
    m__raw_flags = m__io->read_bytes(2);
    m__io__raw_flags = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_flags));
    m_flags = std::unique_ptr<gp_flags_t>(new gp_flags_t(m__io__raw_flags.get(), this, m__root));
    m_compression_method = static_cast<zip_t::compression_t>(m__io->read_u2le());
    m__raw_file_mod_time = m__io->read_bytes(4);
    m__io__raw_file_mod_time = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_file_mod_time));
    m_file_mod_time = std::unique_ptr<dos_datetime_t>(new dos_datetime_t(m__io__raw_file_mod_time.get()));
    m_crc32 = m__io->read_u4le();
    m_len_body_compressed = m__io->read_u4le();
    m_len_body_uncompressed = m__io->read_u4le();
    m_len_file_name = m__io->read_u2le();
    m_len_extra = m__io->read_u2le();
    m_file_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(len_file_name()), std::string("UTF-8"));
    m__raw_extra = m__io->read_bytes(len_extra());
    m__io__raw_extra = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_extra));
    m_extra = std::unique_ptr<extras_t>(new extras_t(m__io__raw_extra.get(), this, m__root));
}

zip_t::local_file_header_t::~local_file_header_t() {
    _clean_up();
}

void zip_t::local_file_header_t::_clean_up() {
}

zip_t::local_file_header_t::gp_flags_t::gp_flags_t(kaitai::kstream* p__io, zip_t::local_file_header_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_deflated_mode = false;
    f_imploded_dict_byte_size = false;
    f_imploded_num_sf_trees = false;
    f_lzma_has_eos_marker = false;
    _read();
}

void zip_t::local_file_header_t::gp_flags_t::_read() {
    m_file_encrypted = m__io->read_bits_int_le(1);
    m_comp_options_raw = m__io->read_bits_int_le(2);
    m_has_data_descriptor = m__io->read_bits_int_le(1);
    m_reserved_1 = m__io->read_bits_int_le(1);
    m_comp_patched_data = m__io->read_bits_int_le(1);
    m_strong_encrypt = m__io->read_bits_int_le(1);
    m_reserved_2 = m__io->read_bits_int_le(4);
    m_lang_encoding = m__io->read_bits_int_le(1);
    m_reserved_3 = m__io->read_bits_int_le(1);
    m_mask_header_values = m__io->read_bits_int_le(1);
    m_reserved_4 = m__io->read_bits_int_le(2);
}

zip_t::local_file_header_t::gp_flags_t::~gp_flags_t() {
    _clean_up();
}

void zip_t::local_file_header_t::gp_flags_t::_clean_up() {
}

zip_t::local_file_header_t::gp_flags_t::deflate_mode_t zip_t::local_file_header_t::gp_flags_t::deflated_mode() {
    if (f_deflated_mode)
        return m_deflated_mode;
    n_deflated_mode = true;
    if ( ((_parent()->compression_method() == zip_t::COMPRESSION_DEFLATED) || (_parent()->compression_method() == zip_t::COMPRESSION_ENHANCED_DEFLATED)) ) {
        n_deflated_mode = false;
        m_deflated_mode = static_cast<zip_t::local_file_header_t::gp_flags_t::deflate_mode_t>(comp_options_raw());
    }
    f_deflated_mode = true;
    return m_deflated_mode;
}

int32_t zip_t::local_file_header_t::gp_flags_t::imploded_dict_byte_size() {
    if (f_imploded_dict_byte_size)
        return m_imploded_dict_byte_size;
    n_imploded_dict_byte_size = true;
    if (_parent()->compression_method() == zip_t::COMPRESSION_IMPLODED) {
        n_imploded_dict_byte_size = false;
        m_imploded_dict_byte_size = ((((comp_options_raw() & 1) != 0) ? (8) : (4)) * 1024);
    }
    f_imploded_dict_byte_size = true;
    return m_imploded_dict_byte_size;
}

int8_t zip_t::local_file_header_t::gp_flags_t::imploded_num_sf_trees() {
    if (f_imploded_num_sf_trees)
        return m_imploded_num_sf_trees;
    n_imploded_num_sf_trees = true;
    if (_parent()->compression_method() == zip_t::COMPRESSION_IMPLODED) {
        n_imploded_num_sf_trees = false;
        m_imploded_num_sf_trees = (((comp_options_raw() & 2) != 0) ? (3) : (2));
    }
    f_imploded_num_sf_trees = true;
    return m_imploded_num_sf_trees;
}

bool zip_t::local_file_header_t::gp_flags_t::lzma_has_eos_marker() {
    if (f_lzma_has_eos_marker)
        return m_lzma_has_eos_marker;
    n_lzma_has_eos_marker = true;
    if (_parent()->compression_method() == zip_t::COMPRESSION_LZMA) {
        n_lzma_has_eos_marker = false;
        m_lzma_has_eos_marker = (comp_options_raw() & 1) != 0;
    }
    f_lzma_has_eos_marker = true;
    return m_lzma_has_eos_marker;
}

zip_t::end_of_central_dir_t::end_of_central_dir_t(kaitai::kstream* p__io, zip_t::pk_section_t* p__parent, zip_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void zip_t::end_of_central_dir_t::_read() {
    m_disk_of_end_of_central_dir = m__io->read_u2le();
    m_disk_of_central_dir = m__io->read_u2le();
    m_num_central_dir_entries_on_disk = m__io->read_u2le();
    m_num_central_dir_entries_total = m__io->read_u2le();
    m_len_central_dir = m__io->read_u4le();
    m_ofs_central_dir = m__io->read_u4le();
    m_len_comment = m__io->read_u2le();
    m_comment = kaitai::kstream::bytes_to_str(m__io->read_bytes(len_comment()), std::string("UTF-8"));
}

zip_t::end_of_central_dir_t::~end_of_central_dir_t() {
    _clean_up();
}

void zip_t::end_of_central_dir_t::_clean_up() {
}