Compressed Macintosh resource data, Apple `'dcmp' (0)` format: C++11/STL parsing library

Compressed resource data in 'dcmp' (0) format, as stored in compressed resources with header type 8 and decompressor ID 0.

The 'dcmp' (0) decompressor resource is included in the System file of System 7.0 and later. This compression format is used for most compressed resources in System 7.0's files. This decompressor is also included with and used by some other Apple applications, such as ResEdit.

This compression format supports some basic general-purpose compression schemes, including backreferences to previous data, run-length encoding, and delta encoding. It also includes some types of compression tailored specifically to Mac OS resources, including a set of single-byte codes that correspond to entries in a hard-coded lookup table, and a specialized kind of delta encoding for segment loader jump tables.

Almost all parts of this compression format operate on units of 2 or 4 bytes. As a result, it is nearly impossible to store data with an odd length in this format. To work around this limitation, odd-length resources are padded with an extra byte before compressing them with this format. This extra byte is ignored after decompression, as the real (odd) length of the resource is stored in the compressed resource header.

The 'dcmp' (1) compression format (see dcmp_1.ksy) is very similar to this format, with the main difference that it operates mostly on single bytes rather than two-byte units.

Application

Mac OS

KS implementation details

License: MIT
Minimal Kaitai Struct required: 0.8

This page hosts a formal specification of Compressed Macintosh resource data, Apple `'dcmp' (0)` format 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.bin", 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:
    dcmp_0_t data(&ks);
    

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

data.chunks() // => The sequence of chunks that make up the compressed data.

C++11/STL source code to parse Compressed Macintosh resource data, Apple `'dcmp' (0)` format

dcmp_0.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 "dcmp_variable_length_integer.h"
#include <vector>

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

/**
 * Compressed resource data in `'dcmp' (0)` format,
 * as stored in compressed resources with header type `8` and decompressor ID `0`.
 * 
 * The `'dcmp' (0)` decompressor resource is included in the System file of System 7.0 and later.
 * This compression format is used for most compressed resources in System 7.0's files.
 * This decompressor is also included with and used by some other Apple applications,
 * such as ResEdit.
 * 
 * This compression format supports some basic general-purpose compression schemes,
 * including backreferences to previous data,
 * run-length encoding,
 * and delta encoding.
 * It also includes some types of compression tailored specifically to Mac OS resources,
 * including a set of single-byte codes that correspond to entries in a hard-coded lookup table,
 * and a specialized kind of delta encoding for segment loader jump tables.
 * 
 * Almost all parts of this compression format operate on units of 2 or 4 bytes.
 * As a result,
 * it is nearly impossible to store data with an odd length in this format.
 * To work around this limitation,
 * odd-length resources are padded with an extra byte before compressing them with this format.
 * This extra byte is ignored after decompression,
 * as the real (odd) length of the resource is stored in the compressed resource header.
 * 
 * The `'dcmp' (1)` compression format (see dcmp_1.ksy) is very similar to this format,
 * with the main difference that it operates mostly on single bytes rather than two-byte units.
 * \sa https://github.com/dgelessus/python-rsrcfork/blob/f891a6e/src/rsrcfork/compress/dcmp0.py Source
 */

class dcmp_0_t : public kaitai::kstruct {

public:
    class chunk_t;

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

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

public:
    ~dcmp_0_t();

    /**
     * A single chunk of compressed data.
     * Each chunk in the compressed data expands to a sequence of bytes in the uncompressed data,
     * except when `tag == 0xff`,
     * which marks the end of the data and does not correspond to any bytes in the uncompressed data.
     * 
     * Most chunks are stateless and always expand to the same data,
     * regardless of where the chunk appears in the sequence.
     * However,
     * some chunks affect the behavior of future chunks,
     * or expand to different data depending on which chunks came before them.
     */

    class chunk_t : public kaitai::kstruct {

    public:
        class literal_body_t;
        class backreference_body_t;
        class table_lookup_body_t;
        class end_body_t;
        class extended_body_t;

        enum tag_kind_t {
            TAG_KIND_INVALID = -1,
            TAG_KIND_LITERAL = 0,
            TAG_KIND_BACKREFERENCE = 1,
            TAG_KIND_TABLE_LOOKUP = 2,
            TAG_KIND_EXTENDED = 3,
            TAG_KIND_END = 4
        };

        chunk_t(kaitai::kstream* p__io, dcmp_0_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

    public:
        ~chunk_t();

        /**
         * The body of a literal data chunk.
         * 
         * The data that this chunk expands to is stored literally in the body (`literal`).
         * Optionally,
         * the literal data may also be stored for use by future backreference chunks (`do_store`).
         * 
         * The length of the literal data is stored as a number of two-byte units.
         * This means that the literal data always has an even length in bytes.
         */

        class literal_body_t : public kaitai::kstruct {

        public:

            literal_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

        public:
            ~literal_body_t();

        private:
            bool f_do_store;
            bool m_do_store;

        public:

            /**
             * Whether this literal should be stored for use by future backreference chunks.
             * 
             * See the documentation of the `backreference_body` type for details about backreference chunks.
             */
            bool do_store();

        private:
            bool f_len_literal_div2;
            int32_t m_len_literal_div2;

        public:

            /**
             * The length of the literal data,
             * in two-byte units.
             * 
             * In practice,
             * this value is always greater than zero,
             * as there is no use in storing a zero-length literal.
             */
            int32_t len_literal_div2();

        private:
            bool f_len_literal;
            int32_t m_len_literal;

        public:

            /**
             * The length of the literal data,
             * in bytes.
             */
            int32_t len_literal();

        private:
            bool f_len_literal_div2_in_tag;
            int32_t m_len_literal_div2_in_tag;

        public:

            /**
             * The part of the tag byte that indicates the length of the literal data,
             * in two-byte units.
             * If this value is 0,
             * the length is stored in a separate byte after the tag byte and before the literal data.
             */
            int32_t len_literal_div2_in_tag();

        private:
            bool f_is_len_literal_div2_separate;
            bool m_is_len_literal_div2_separate;

        public:

            /**
             * Whether the length of the literal is stored separately from the tag.
             */
            bool is_len_literal_div2_separate();

        private:
            uint8_t m_len_literal_div2_separate;
            bool n_len_literal_div2_separate;

        public:
            bool _is_null_len_literal_div2_separate() { len_literal_div2_separate(); return n_len_literal_div2_separate; };

        private:
            std::string m_literal;
            uint8_t m_tag;
            dcmp_0_t* m__root;
            dcmp_0_t::chunk_t* m__parent;

        public:

            /**
             * The length of the literal data,
             * in two-byte units.
             * 
             * This field is only present if the tag byte's low nibble is zero.
             * In practice,
             * this only happens if the length is 0x10 or greater,
             * because smaller lengths can be encoded into the tag byte.
             */
            uint8_t len_literal_div2_separate() const { return m_len_literal_div2_separate; }

            /**
             * The literal data.
             */
            std::string literal() const { return m_literal; }

            /**
             * The tag byte preceding this chunk body.
             */
            uint8_t tag() const { return m_tag; }
            dcmp_0_t* _root() const { return m__root; }
            dcmp_0_t::chunk_t* _parent() const { return m__parent; }
        };

        /**
         * The body of a backreference chunk.
         * 
         * This chunk expands to the data stored in a preceding literal chunk,
         * indicated by an index number (`index`).
         */

        class backreference_body_t : public kaitai::kstruct {

        public:

            backreference_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

        public:
            ~backreference_body_t();

        private:
            bool f_is_index_separate;
            bool m_is_index_separate;

        public:

            /**
             * Whether the index is stored separately from the tag.
             */
            bool is_index_separate();

        private:
            bool f_index_in_tag;
            int32_t m_index_in_tag;

        public:

            /**
             * The index of the referenced literal chunk,
             * as stored in the tag byte.
             */
            int32_t index_in_tag();

        private:
            bool f_index_separate;
            int32_t m_index_separate;
            bool n_index_separate;

        public:
            bool _is_null_index_separate() { index_separate(); return n_index_separate; };

        private:

        public:

            /**
             * The index of the referenced literal chunk,
             * as stored separately from the tag byte,
             * with the implicit offset corrected for.
             */
            int32_t index_separate();

        private:
            bool f_index;
            int32_t m_index;

        public:

            /**
             * The index of the referenced literal chunk.
             * 
             * Stored literals are assigned index numbers in the order in which they appear in the compressed data,
             * starting at 0.
             * Non-stored literals are not counted in the numbering and cannot be referenced using backreferences.
             * Once an index is assigned to a stored literal,
             * it is never changed or unassigned for the entire length of the compressed data.
             * 
             * As the name indicates,
             * a backreference can only reference stored literal chunks found *before* the backreference,
             * not ones that come after it.
             */
            int32_t index();

        private:
            uint16_t m_index_separate_minus;
            bool n_index_separate_minus;

        public:
            bool _is_null_index_separate_minus() { index_separate_minus(); return n_index_separate_minus; };

        private:
            uint8_t m_tag;
            dcmp_0_t* m__root;
            dcmp_0_t::chunk_t* m__parent;

        public:

            /**
             * The index of the referenced literal chunk,
             * stored separately from the tag.
             * The value in this field is stored minus 0x28.
             * If the tag byte is 0x21,
             * the value is also stored minus 0x100,
             * *on top of* the regular offset
             * (i. e. minus 0x128 in total).
             * 
             * In other words,
             * for tag bytes 0x20 and 0x21,
             * the index is actually 9 bits large,
             * with the low 8 bits stored separately and the highest bit stored in the lowest bit of the tag byte.
             * 
             * This field is only present if the tag byte is 0x20 through 0x22.
             * For higher tag bytes,
             * the index is encoded in the tag byte.
             * Values smaller than 0x28 cannot be stored in this field,
             * they must always be encoded in the tag byte.
             */
            uint16_t index_separate_minus() const { return m_index_separate_minus; }

            /**
             * The tag byte preceding this chunk body.
             */
            uint8_t tag() const { return m_tag; }
            dcmp_0_t* _root() const { return m__root; }
            dcmp_0_t::chunk_t* _parent() const { return m__parent; }
        };

        /**
         * The body of a table lookup chunk.
         * This body is always empty.
         * 
         * This chunk always expands to two bytes (`value`),
         * determined from the tag byte using a fixed lookup table (`lookup_table`).
         * This lookup table is hardcoded in the decompressor and always the same for all compressed data.
         */

        class table_lookup_body_t : public kaitai::kstruct {

        public:

            table_lookup_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

        public:
            ~table_lookup_body_t();

        private:
            bool f_lookup_table;
            std::unique_ptr<std::vector<std::string>> m_lookup_table;

        public:

            /**
             * Fixed lookup table that maps tag byte numbers to two bytes each.
             * 
             * The entries in the lookup table are offset -
             * index 0 stands for tag 0x4b, 1 for 0x4c, etc.
             */
            std::vector<std::string>* lookup_table();

        private:
            bool f_value;
            std::string m_value;

        public:

            /**
             * The two bytes that the tag byte expands to,
             * based on the fixed lookup table.
             */
            std::string value();

        private:
            uint8_t m_tag;
            dcmp_0_t* m__root;
            dcmp_0_t::chunk_t* m__parent;

        public:

            /**
             * The tag byte preceding this chunk body.
             */
            uint8_t tag() const { return m_tag; }
            dcmp_0_t* _root() const { return m__root; }
            dcmp_0_t::chunk_t* _parent() const { return m__parent; }
        };

        /**
         * The body of an end chunk.
         * This body is always empty.
         * 
         * The last chunk in the compressed data must always be an end chunk.
         * An end chunk cannot appear elsewhere in the compressed data.
         */

        class end_body_t : public kaitai::kstruct {

        public:

            end_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

        public:
            ~end_body_t();

        private:
            dcmp_0_t* m__root;
            dcmp_0_t::chunk_t* m__parent;

        public:
            dcmp_0_t* _root() const { return m__root; }
            dcmp_0_t::chunk_t* _parent() const { return m__parent; }
        };

        /**
         * The body of an extended chunk.
         * The meaning of this chunk depends on the extended tag byte stored in the chunk data.
         */

        class extended_body_t : public kaitai::kstruct {

        public:
            class jump_table_body_t;
            class repeat_body_t;
            class delta_encoding_16_bit_body_t;
            class delta_encoding_32_bit_body_t;

            extended_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

        public:
            ~extended_body_t();

            /**
             * The body of a jump table chunk.
             * 
             * This chunk generates parts of a segment loader jump table,
             * in the format found in `'CODE' (0)` resources.
             * It expands to the following data,
             * with all non-constant numbers encoded as unsigned 16-bit big-endian integers:
             * 
             * * `0x3f 0x3c` (push following segment number onto stack)
             * * The segment number
             * * `0xa9 0xf0` (`_LoadSeg` trap)
             * * For each address:
             *   * The address
             *   * `0x3f 0x3c` (push following segment number onto stack)
             *   * The segment number
             *   * `0xa9 0xf0` (`_LoadSeg` trap)
             * 
             * Note that this generates one jump table entry without an address before it,
             * meaning that this address needs to be generated by the preceding chunk.
             * All following jump table entries are generated with the addresses encoded in this chunk.
             */

            class jump_table_body_t : public kaitai::kstruct {

            public:

                jump_table_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

            public:
                ~jump_table_body_t();

            private:
                bool f_segment_number;
                int32_t m_segment_number;

            public:

                /**
                 * The segment number for all of the generated jump table entries.
                 * 
                 * Although it is stored as a variable-length integer,
                 * the segment number must be in the range `0x0 <= x <= 0xffff`,
                 * i. e. an unsigned 16-bit integer.
                 */
                int32_t segment_number();

            private:
                bool f_num_addresses;
                int32_t m_num_addresses;

            public:

                /**
                 * The number of addresses stored in this chunk.
                 * 
                 * This number must be greater than 0.
                 */
                int32_t num_addresses();

            private:
                std::unique_ptr<dcmp_variable_length_integer_t> m_segment_number_raw;
                std::unique_ptr<dcmp_variable_length_integer_t> m_num_addresses_raw;
                std::unique_ptr<std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>> m_addresses_raw;
                dcmp_0_t* m__root;
                dcmp_0_t::chunk_t::extended_body_t* m__parent;

            public:

                /**
                 * Raw variable-length integer representation of `segment_number`.
                 */
                dcmp_variable_length_integer_t* segment_number_raw() const { return m_segment_number_raw.get(); }

                /**
                 * Raw variable-length integer representation of `num_addresses`.
                 */
                dcmp_variable_length_integer_t* num_addresses_raw() const { return m_num_addresses_raw.get(); }

                /**
                 * The addresses for each generated jump table entry,
                 * stored as variable-length integers.
                 * 
                 * The first address is stored literally and must be in the range `0x0 <= x <= 0xffff`,
                 * i. e. an unsigned 16-bit integer.
                 * 
                 * All following addresses are stored as deltas relative to the previous address.
                 * Each of these deltas is stored plus 6;
                 * this value needs to be subtracted before (or after) adding it to the previous address.
                 * 
                 * Each delta (after subtracting 6) should be positive,
                 * and adding it to the previous address should not result in a value larger than `0xffff`,
                 * i. e. there should be no 16-bit unsigned integer wraparound.
                 * These conditions are always met in all known jump table chunks,
                 * so it is not known how the original decompressor behaves otherwise.
                 */
                std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>* addresses_raw() const { return m_addresses_raw.get(); }
                dcmp_0_t* _root() const { return m__root; }
                dcmp_0_t::chunk_t::extended_body_t* _parent() const { return m__parent; }
            };

            /**
             * The body of a repeat chunk.
             * 
             * This chunk expands to a 1-byte or 2-byte value repeated a number of times,
             * i. e. it implements a form of run-length encoding.
             */

            class repeat_body_t : public kaitai::kstruct {

            public:

                repeat_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

            public:
                ~repeat_body_t();

            private:
                bool f_byte_count;
                int32_t m_byte_count;

            public:

                /**
                 * The length in bytes of the value to be repeated.
                 * Regardless of the byte count,
                 * the value to be repeated is stored as a variable-length integer.
                 */
                int32_t byte_count();

            private:
                bool f_to_repeat;
                int32_t m_to_repeat;

            public:

                /**
                 * The value to repeat.
                 * 
                 * Although it is stored as a variable-length integer,
                 * this value must fit into an unsigned big-endian integer that is as long as `byte_count`,
                 * i. e. either 8 or 16 bits.
                 */
                int32_t to_repeat();

            private:
                bool f_repeat_count_m1;
                int32_t m_repeat_count_m1;

            public:

                /**
                 * The number of times to repeat the value,
                 * minus one.
                 * 
                 * This value must not be negative.
                 */
                int32_t repeat_count_m1();

            private:
                bool f_repeat_count;
                int32_t m_repeat_count;

            public:

                /**
                 * The number of times to repeat the value.
                 * 
                 * This value must be positive.
                 */
                int32_t repeat_count();

            private:
                std::unique_ptr<dcmp_variable_length_integer_t> m_to_repeat_raw;
                std::unique_ptr<dcmp_variable_length_integer_t> m_repeat_count_m1_raw;
                uint8_t m_tag;
                dcmp_0_t* m__root;
                dcmp_0_t::chunk_t::extended_body_t* m__parent;

            public:

                /**
                 * Raw variable-length integer representation of `to_repeat`.
                 */
                dcmp_variable_length_integer_t* to_repeat_raw() const { return m_to_repeat_raw.get(); }

                /**
                 * Raw variable-length integer representation of `repeat_count_m1`.
                 */
                dcmp_variable_length_integer_t* repeat_count_m1_raw() const { return m_repeat_count_m1_raw.get(); }

                /**
                 * The extended tag byte preceding this chunk body.
                 */
                uint8_t tag() const { return m_tag; }
                dcmp_0_t* _root() const { return m__root; }
                dcmp_0_t::chunk_t::extended_body_t* _parent() const { return m__parent; }
            };

            /**
             * The body of a 16-bit delta encoding chunk.
             * 
             * This chunk expands to a sequence of 16-bit big-endian integer values.
             * The first value is stored literally.
             * All following values are stored as deltas relative to the previous value.
             */

            class delta_encoding_16_bit_body_t : public kaitai::kstruct {

            public:

                delta_encoding_16_bit_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

            public:
                ~delta_encoding_16_bit_body_t();

            private:
                bool f_first_value;
                int32_t m_first_value;

            public:

                /**
                 * The first value in the sequence.
                 * 
                 * Although it is stored as a variable-length integer,
                 * this value must be in the range `-0x8000 <= x <= 0x7fff`,
                 * i. e. a signed 16-bit integer.
                 */
                int32_t first_value();

            private:
                bool f_num_deltas;
                int32_t m_num_deltas;

            public:

                /**
                 * The number of deltas stored in this chunk.
                 * 
                 * This number must not be negative.
                 */
                int32_t num_deltas();

            private:
                std::unique_ptr<dcmp_variable_length_integer_t> m_first_value_raw;
                std::unique_ptr<dcmp_variable_length_integer_t> m_num_deltas_raw;
                std::unique_ptr<std::vector<int8_t>> m_deltas;
                dcmp_0_t* m__root;
                dcmp_0_t::chunk_t::extended_body_t* m__parent;

            public:

                /**
                 * Raw variable-length integer representation of `first_value`.
                 */
                dcmp_variable_length_integer_t* first_value_raw() const { return m_first_value_raw.get(); }

                /**
                 * Raw variable-length integer representation of `num_deltas`.
                 */
                dcmp_variable_length_integer_t* num_deltas_raw() const { return m_num_deltas_raw.get(); }

                /**
                 * The deltas for each value relative to the previous value.
                 * 
                 * Each of these deltas is a signed 8-bit value.
                 * When adding the delta to the previous value,
                 * 16-bit integer wraparound is performed if necessary,
                 * so that the resulting value always fits into a 16-bit signed integer.
                 */
                std::vector<int8_t>* deltas() const { return m_deltas.get(); }
                dcmp_0_t* _root() const { return m__root; }
                dcmp_0_t::chunk_t::extended_body_t* _parent() const { return m__parent; }
            };

            /**
             * The body of a 32-bit delta encoding chunk.
             * 
             * This chunk expands to a sequence of 32-bit big-endian integer values.
             * The first value is stored literally.
             * All following values are stored as deltas relative to the previous value.
             */

            class delta_encoding_32_bit_body_t : public kaitai::kstruct {

            public:

                delta_encoding_32_bit_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent = nullptr, dcmp_0_t* p__root = nullptr);

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

            public:
                ~delta_encoding_32_bit_body_t();

            private:
                bool f_first_value;
                int32_t m_first_value;

            public:

                /**
                 * The first value in the sequence.
                 */
                int32_t first_value();

            private:
                bool f_num_deltas;
                int32_t m_num_deltas;

            public:

                /**
                 * The number of deltas stored in this chunk.
                 * 
                 * This number must not be negative.
                 */
                int32_t num_deltas();

            private:
                std::unique_ptr<dcmp_variable_length_integer_t> m_first_value_raw;
                std::unique_ptr<dcmp_variable_length_integer_t> m_num_deltas_raw;
                std::unique_ptr<std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>> m_deltas_raw;
                dcmp_0_t* m__root;
                dcmp_0_t::chunk_t::extended_body_t* m__parent;

            public:

                /**
                 * Raw variable-length integer representation of `first_value`.
                 */
                dcmp_variable_length_integer_t* first_value_raw() const { return m_first_value_raw.get(); }

                /**
                 * Raw variable-length integer representation of `num_deltas`.
                 */
                dcmp_variable_length_integer_t* num_deltas_raw() const { return m_num_deltas_raw.get(); }

                /**
                 * The deltas for each value relative to the previous value,
                 * stored as variable-length integers.
                 * 
                 * Each of these deltas is a signed value.
                 * When adding the delta to the previous value,
                 * 32-bit integer wraparound is performed if necessary,
                 * so that the resulting value always fits into a 32-bit signed integer.
                 */
                std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>* deltas_raw() const { return m_deltas_raw.get(); }
                dcmp_0_t* _root() const { return m__root; }
                dcmp_0_t::chunk_t::extended_body_t* _parent() const { return m__parent; }
            };

        private:
            uint8_t m_tag;
            std::unique_ptr<kaitai::kstruct> m_body;
            bool n_body;

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

        private:
            dcmp_0_t* m__root;
            dcmp_0_t::chunk_t* m__parent;

        public:

            /**
             * The chunk's extended tag byte.
             * This controls the structure of the body and the meaning of the chunk.
             */
            uint8_t tag() const { return m_tag; }

            /**
             * The chunk's body.
             */
            kaitai::kstruct* body() const { return m_body.get(); }
            dcmp_0_t* _root() const { return m__root; }
            dcmp_0_t::chunk_t* _parent() const { return m__parent; }
        };

    private:
        uint8_t m_tag;
        std::unique_ptr<kaitai::kstruct> m_body;
        bool n_body;

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

    private:
        dcmp_0_t* m__root;
        dcmp_0_t* m__parent;

    public:

        /**
         * The chunk's tag byte.
         * This controls the structure of the body and the meaning of the chunk.
         */
        uint8_t tag() const { return m_tag; }

        /**
         * The chunk's body.
         * 
         * Certain chunks do not have any data following the tag byte.
         * In this case,
         * the body is a zero-length structure.
         */
        kaitai::kstruct* body() const { return m_body.get(); }
        dcmp_0_t* _root() const { return m__root; }
        dcmp_0_t* _parent() const { return m__parent; }
    };

private:
    std::unique_ptr<std::vector<std::unique_ptr<chunk_t>>> m_chunks;
    dcmp_0_t* m__root;
    kaitai::kstruct* m__parent;

public:

    /**
     * The sequence of chunks that make up the compressed data.
     */
    std::vector<std::unique_ptr<chunk_t>>* chunks() const { return m_chunks.get(); }
    dcmp_0_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

dcmp_0.cpp

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

#include "dcmp_0.h"

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

void dcmp_0_t::_read() {
    m_chunks = std::unique_ptr<std::vector<std::unique_ptr<chunk_t>>>(new std::vector<std::unique_ptr<chunk_t>>());
    {
        int i = 0;
        chunk_t* _;
        do {
            _ = new chunk_t(m__io, this, m__root);
            m_chunks->push_back(std::move(std::unique_ptr<chunk_t>(_)));
            i++;
        } while (!(_->tag() == 255));
    }
}

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

void dcmp_0_t::_clean_up() {
}

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

void dcmp_0_t::chunk_t::_read() {
    m_tag = m__io->read_u1();
    n_body = true;
    switch ((( ((tag() >= 0) && (tag() <= 31)) ) ? (dcmp_0_t::chunk_t::TAG_KIND_LITERAL) : ((( ((tag() >= 32) && (tag() <= 74)) ) ? (dcmp_0_t::chunk_t::TAG_KIND_BACKREFERENCE) : ((( ((tag() >= 75) && (tag() <= 253)) ) ? (dcmp_0_t::chunk_t::TAG_KIND_TABLE_LOOKUP) : (((tag() == 254) ? (dcmp_0_t::chunk_t::TAG_KIND_EXTENDED) : (((tag() == 255) ? (dcmp_0_t::chunk_t::TAG_KIND_END) : (dcmp_0_t::chunk_t::TAG_KIND_INVALID))))))))))) {
    case dcmp_0_t::chunk_t::TAG_KIND_EXTENDED: {
        n_body = false;
        m_body = std::unique_ptr<extended_body_t>(new extended_body_t(m__io, this, m__root));
        break;
    }
    case dcmp_0_t::chunk_t::TAG_KIND_LITERAL: {
        n_body = false;
        m_body = std::unique_ptr<literal_body_t>(new literal_body_t(tag(), m__io, this, m__root));
        break;
    }
    case dcmp_0_t::chunk_t::TAG_KIND_END: {
        n_body = false;
        m_body = std::unique_ptr<end_body_t>(new end_body_t(m__io, this, m__root));
        break;
    }
    case dcmp_0_t::chunk_t::TAG_KIND_TABLE_LOOKUP: {
        n_body = false;
        m_body = std::unique_ptr<table_lookup_body_t>(new table_lookup_body_t(tag(), m__io, this, m__root));
        break;
    }
    case dcmp_0_t::chunk_t::TAG_KIND_BACKREFERENCE: {
        n_body = false;
        m_body = std::unique_ptr<backreference_body_t>(new backreference_body_t(tag(), m__io, this, m__root));
        break;
    }
    }
}

dcmp_0_t::chunk_t::~chunk_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::_clean_up() {
    if (!n_body) {
    }
}

dcmp_0_t::chunk_t::literal_body_t::literal_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_tag = p_tag;
    f_do_store = false;
    f_len_literal_div2 = false;
    f_len_literal = false;
    f_len_literal_div2_in_tag = false;
    f_is_len_literal_div2_separate = false;
    _read();
}

void dcmp_0_t::chunk_t::literal_body_t::_read() {
    n_len_literal_div2_separate = true;
    if (is_len_literal_div2_separate()) {
        n_len_literal_div2_separate = false;
        m_len_literal_div2_separate = m__io->read_u1();
    }
    m_literal = m__io->read_bytes(len_literal());
}

dcmp_0_t::chunk_t::literal_body_t::~literal_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::literal_body_t::_clean_up() {
    if (!n_len_literal_div2_separate) {
    }
}

bool dcmp_0_t::chunk_t::literal_body_t::do_store() {
    if (f_do_store)
        return m_do_store;
    m_do_store = (tag() & 16) != 0;
    f_do_store = true;
    return m_do_store;
}

int32_t dcmp_0_t::chunk_t::literal_body_t::len_literal_div2() {
    if (f_len_literal_div2)
        return m_len_literal_div2;
    m_len_literal_div2 = ((is_len_literal_div2_separate()) ? (len_literal_div2_separate()) : (len_literal_div2_in_tag()));
    f_len_literal_div2 = true;
    return m_len_literal_div2;
}

int32_t dcmp_0_t::chunk_t::literal_body_t::len_literal() {
    if (f_len_literal)
        return m_len_literal;
    m_len_literal = (len_literal_div2() * 2);
    f_len_literal = true;
    return m_len_literal;
}

int32_t dcmp_0_t::chunk_t::literal_body_t::len_literal_div2_in_tag() {
    if (f_len_literal_div2_in_tag)
        return m_len_literal_div2_in_tag;
    m_len_literal_div2_in_tag = (tag() & 15);
    f_len_literal_div2_in_tag = true;
    return m_len_literal_div2_in_tag;
}

bool dcmp_0_t::chunk_t::literal_body_t::is_len_literal_div2_separate() {
    if (f_is_len_literal_div2_separate)
        return m_is_len_literal_div2_separate;
    m_is_len_literal_div2_separate = len_literal_div2_in_tag() == 0;
    f_is_len_literal_div2_separate = true;
    return m_is_len_literal_div2_separate;
}

dcmp_0_t::chunk_t::backreference_body_t::backreference_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_tag = p_tag;
    f_is_index_separate = false;
    f_index_in_tag = false;
    f_index_separate = false;
    f_index = false;
    _read();
}

void dcmp_0_t::chunk_t::backreference_body_t::_read() {
    n_index_separate_minus = true;
    if (is_index_separate()) {
        n_index_separate_minus = false;
        n_index_separate_minus = true;
        switch (tag()) {
        case 32: {
            n_index_separate_minus = false;
            m_index_separate_minus = m__io->read_u1();
            break;
        }
        case 33: {
            n_index_separate_minus = false;
            m_index_separate_minus = m__io->read_u1();
            break;
        }
        case 34: {
            n_index_separate_minus = false;
            m_index_separate_minus = m__io->read_u2be();
            break;
        }
        }
    }
}

dcmp_0_t::chunk_t::backreference_body_t::~backreference_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::backreference_body_t::_clean_up() {
    if (!n_index_separate_minus) {
    }
}

bool dcmp_0_t::chunk_t::backreference_body_t::is_index_separate() {
    if (f_is_index_separate)
        return m_is_index_separate;
    m_is_index_separate =  ((tag() >= 32) && (tag() <= 34)) ;
    f_is_index_separate = true;
    return m_is_index_separate;
}

int32_t dcmp_0_t::chunk_t::backreference_body_t::index_in_tag() {
    if (f_index_in_tag)
        return m_index_in_tag;
    m_index_in_tag = (tag() - 35);
    f_index_in_tag = true;
    return m_index_in_tag;
}

int32_t dcmp_0_t::chunk_t::backreference_body_t::index_separate() {
    if (f_index_separate)
        return m_index_separate;
    n_index_separate = true;
    if (is_index_separate()) {
        n_index_separate = false;
        m_index_separate = ((index_separate_minus() + 40) + ((tag() == 33) ? (256) : (0)));
    }
    f_index_separate = true;
    return m_index_separate;
}

int32_t dcmp_0_t::chunk_t::backreference_body_t::index() {
    if (f_index)
        return m_index;
    m_index = ((is_index_separate()) ? (index_separate()) : (index_in_tag()));
    f_index = true;
    return m_index;
}

dcmp_0_t::chunk_t::table_lookup_body_t::table_lookup_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_tag = p_tag;
    f_lookup_table = false;
    f_value = false;
    _read();
}

void dcmp_0_t::chunk_t::table_lookup_body_t::_read() {
}

dcmp_0_t::chunk_t::table_lookup_body_t::~table_lookup_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::table_lookup_body_t::_clean_up() {
}

std::vector<std::string>* dcmp_0_t::chunk_t::table_lookup_body_t::lookup_table() {
    if (f_lookup_table)
        return m_lookup_table.get();
    m_lookup_table = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>{std::string("\x00\x00", 2), std::string("\x4E\xBA", 2), std::string("\x00\x08", 2), std::string("\x4E\x75", 2), std::string("\x00\x0C", 2), std::string("\x4E\xAD", 2), std::string("\x20\x53", 2), std::string("\x2F\x0B", 2), std::string("\x61\x00", 2), std::string("\x00\x10", 2), std::string("\x70\x00", 2), std::string("\x2F\x00", 2), std::string("\x48\x6E", 2), std::string("\x20\x50", 2), std::string("\x20\x6E", 2), std::string("\x2F\x2E", 2), std::string("\xFF\xFC", 2), std::string("\x48\xE7", 2), std::string("\x3F\x3C", 2), std::string("\x00\x04", 2), std::string("\xFF\xF8", 2), std::string("\x2F\x0C", 2), std::string("\x20\x06", 2), std::string("\x4E\xED", 2), std::string("\x4E\x56", 2), std::string("\x20\x68", 2), std::string("\x4E\x5E", 2), std::string("\x00\x01", 2), std::string("\x58\x8F", 2), std::string("\x4F\xEF", 2), std::string("\x00\x02", 2), std::string("\x00\x18", 2), std::string("\x60\x00", 2), std::string("\xFF\xFF", 2), std::string("\x50\x8F", 2), std::string("\x4E\x90", 2), std::string("\x00\x06", 2), std::string("\x26\x6E", 2), std::string("\x00\x14", 2), std::string("\xFF\xF4", 2), std::string("\x4C\xEE", 2), std::string("\x00\x0A", 2), std::string("\x00\x0E", 2), std::string("\x41\xEE", 2), std::string("\x4C\xDF", 2), std::string("\x48\xC0", 2), std::string("\xFF\xF0", 2), std::string("\x2D\x40", 2), std::string("\x00\x12", 2), std::string("\x30\x2E", 2), std::string("\x70\x01", 2), std::string("\x2F\x28", 2), std::string("\x20\x54", 2), std::string("\x67\x00", 2), std::string("\x00\x20", 2), std::string("\x00\x1C", 2), std::string("\x20\x5F", 2), std::string("\x18\x00", 2), std::string("\x26\x6F", 2), std::string("\x48\x78", 2), std::string("\x00\x16", 2), std::string("\x41\xFA", 2), std::string("\x30\x3C", 2), std::string("\x28\x40", 2), std::string("\x72\x00", 2), std::string("\x28\x6E", 2), std::string("\x20\x0C", 2), std::string("\x66\x00", 2), std::string("\x20\x6B", 2), std::string("\x2F\x07", 2), std::string("\x55\x8F", 2), std::string("\x00\x28", 2), std::string("\xFF\xFE", 2), std::string("\xFF\xEC", 2), std::string("\x22\xD8", 2), std::string("\x20\x0B", 2), std::string("\x00\x0F", 2), std::string("\x59\x8F", 2), std::string("\x2F\x3C", 2), std::string("\xFF\x00", 2), std::string("\x01\x18", 2), std::string("\x81\xE1", 2), std::string("\x4A\x00", 2), std::string("\x4E\xB0", 2), std::string("\xFF\xE8", 2), std::string("\x48\xC7", 2), std::string("\x00\x03", 2), std::string("\x00\x22", 2), std::string("\x00\x07", 2), std::string("\x00\x1A", 2), std::string("\x67\x06", 2), std::string("\x67\x08", 2), std::string("\x4E\xF9", 2), std::string("\x00\x24", 2), std::string("\x20\x78", 2), std::string("\x08\x00", 2), std::string("\x66\x04", 2), std::string("\x00\x2A", 2), std::string("\x4E\xD0", 2), std::string("\x30\x28", 2), std::string("\x26\x5F", 2), std::string("\x67\x04", 2), std::string("\x00\x30", 2), std::string("\x43\xEE", 2), std::string("\x3F\x00", 2), std::string("\x20\x1F", 2), std::string("\x00\x1E", 2), std::string("\xFF\xF6", 2), std::string("\x20\x2E", 2), std::string("\x42\xA7", 2), std::string("\x20\x07", 2), std::string("\xFF\xFA", 2), std::string("\x60\x02", 2), std::string("\x3D\x40", 2), std::string("\x0C\x40", 2), std::string("\x66\x06", 2), std::string("\x00\x26", 2), std::string("\x2D\x48", 2), std::string("\x2F\x01", 2), std::string("\x70\xFF", 2), std::string("\x60\x04", 2), std::string("\x18\x80", 2), std::string("\x4A\x40", 2), std::string("\x00\x40", 2), std::string("\x00\x2C", 2), std::string("\x2F\x08", 2), std::string("\x00\x11", 2), std::string("\xFF\xE4", 2), std::string("\x21\x40", 2), std::string("\x26\x40", 2), std::string("\xFF\xF2", 2), std::string("\x42\x6E", 2), std::string("\x4E\xB9", 2), std::string("\x3D\x7C", 2), std::string("\x00\x38", 2), std::string("\x00\x0D", 2), std::string("\x60\x06", 2), std::string("\x42\x2E", 2), std::string("\x20\x3C", 2), std::string("\x67\x0C", 2), std::string("\x2D\x68", 2), std::string("\x66\x08", 2), std::string("\x4A\x2E", 2), std::string("\x4A\xAE", 2), std::string("\x00\x2E", 2), std::string("\x48\x40", 2), std::string("\x22\x5F", 2), std::string("\x22\x00", 2), std::string("\x67\x0A", 2), std::string("\x30\x07", 2), std::string("\x42\x67", 2), std::string("\x00\x32", 2), std::string("\x20\x28", 2), std::string("\x00\x09", 2), std::string("\x48\x7A", 2), std::string("\x02\x00", 2), std::string("\x2F\x2B", 2), std::string("\x00\x05", 2), std::string("\x22\x6E", 2), std::string("\x66\x02", 2), std::string("\xE5\x80", 2), std::string("\x67\x0E", 2), std::string("\x66\x0A", 2), std::string("\x00\x50", 2), std::string("\x3E\x00", 2), std::string("\x66\x0C", 2), std::string("\x2E\x00", 2), std::string("\xFF\xEE", 2), std::string("\x20\x6D", 2), std::string("\x20\x40", 2), std::string("\xFF\xE0", 2), std::string("\x53\x40", 2), std::string("\x60\x08", 2), std::string("\x04\x80", 2), std::string("\x00\x68", 2), std::string("\x0B\x7C", 2), std::string("\x44\x00", 2), std::string("\x41\xE8", 2), std::string("\x48\x41", 2)});
    f_lookup_table = true;
    return m_lookup_table.get();
}

std::string dcmp_0_t::chunk_t::table_lookup_body_t::value() {
    if (f_value)
        return m_value;
    m_value = lookup_table()->at((tag() - 75));
    f_value = true;
    return m_value;
}

dcmp_0_t::chunk_t::end_body_t::end_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void dcmp_0_t::chunk_t::end_body_t::_read() {
}

dcmp_0_t::chunk_t::end_body_t::~end_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::end_body_t::_clean_up() {
}

dcmp_0_t::chunk_t::extended_body_t::extended_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void dcmp_0_t::chunk_t::extended_body_t::_read() {
    m_tag = m__io->read_u1();
    n_body = true;
    switch (tag()) {
    case 0: {
        n_body = false;
        m_body = std::unique_ptr<jump_table_body_t>(new jump_table_body_t(m__io, this, m__root));
        break;
    }
    case 4: {
        n_body = false;
        m_body = std::unique_ptr<delta_encoding_16_bit_body_t>(new delta_encoding_16_bit_body_t(m__io, this, m__root));
        break;
    }
    case 6: {
        n_body = false;
        m_body = std::unique_ptr<delta_encoding_32_bit_body_t>(new delta_encoding_32_bit_body_t(m__io, this, m__root));
        break;
    }
    case 3: {
        n_body = false;
        m_body = std::unique_ptr<repeat_body_t>(new repeat_body_t(tag(), m__io, this, m__root));
        break;
    }
    case 2: {
        n_body = false;
        m_body = std::unique_ptr<repeat_body_t>(new repeat_body_t(tag(), m__io, this, m__root));
        break;
    }
    }
}

dcmp_0_t::chunk_t::extended_body_t::~extended_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::extended_body_t::_clean_up() {
    if (!n_body) {
    }
}

dcmp_0_t::chunk_t::extended_body_t::jump_table_body_t::jump_table_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_segment_number_raw = nullptr;
    m_num_addresses_raw = nullptr;
    m_addresses_raw = nullptr;
    f_segment_number = false;
    f_num_addresses = false;
    _read();
}

void dcmp_0_t::chunk_t::extended_body_t::jump_table_body_t::_read() {
    m_segment_number_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_num_addresses_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_addresses_raw = std::unique_ptr<std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>>(new std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>());
    const int l_addresses_raw = num_addresses();
    for (int i = 0; i < l_addresses_raw; i++) {
        m_addresses_raw->push_back(std::move(std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io))));
    }
}

dcmp_0_t::chunk_t::extended_body_t::jump_table_body_t::~jump_table_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::extended_body_t::jump_table_body_t::_clean_up() {
}

int32_t dcmp_0_t::chunk_t::extended_body_t::jump_table_body_t::segment_number() {
    if (f_segment_number)
        return m_segment_number;
    m_segment_number = segment_number_raw()->value();
    f_segment_number = true;
    return m_segment_number;
}

int32_t dcmp_0_t::chunk_t::extended_body_t::jump_table_body_t::num_addresses() {
    if (f_num_addresses)
        return m_num_addresses;
    m_num_addresses = num_addresses_raw()->value();
    f_num_addresses = true;
    return m_num_addresses;
}

dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::repeat_body_t(uint8_t p_tag, kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_tag = p_tag;
    m_to_repeat_raw = nullptr;
    m_repeat_count_m1_raw = nullptr;
    f_byte_count = false;
    f_to_repeat = false;
    f_repeat_count_m1 = false;
    f_repeat_count = false;
    _read();
}

void dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::_read() {
    m_to_repeat_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_repeat_count_m1_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
}

dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::~repeat_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::_clean_up() {
}

int32_t dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::byte_count() {
    if (f_byte_count)
        return m_byte_count;
    m_byte_count = ((tag() == 2) ? (1) : (((tag() == 3) ? (2) : (-1))));
    f_byte_count = true;
    return m_byte_count;
}

int32_t dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::to_repeat() {
    if (f_to_repeat)
        return m_to_repeat;
    m_to_repeat = to_repeat_raw()->value();
    f_to_repeat = true;
    return m_to_repeat;
}

int32_t dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::repeat_count_m1() {
    if (f_repeat_count_m1)
        return m_repeat_count_m1;
    m_repeat_count_m1 = repeat_count_m1_raw()->value();
    f_repeat_count_m1 = true;
    return m_repeat_count_m1;
}

int32_t dcmp_0_t::chunk_t::extended_body_t::repeat_body_t::repeat_count() {
    if (f_repeat_count)
        return m_repeat_count;
    m_repeat_count = (repeat_count_m1() + 1);
    f_repeat_count = true;
    return m_repeat_count;
}

dcmp_0_t::chunk_t::extended_body_t::delta_encoding_16_bit_body_t::delta_encoding_16_bit_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_first_value_raw = nullptr;
    m_num_deltas_raw = nullptr;
    m_deltas = nullptr;
    f_first_value = false;
    f_num_deltas = false;
    _read();
}

void dcmp_0_t::chunk_t::extended_body_t::delta_encoding_16_bit_body_t::_read() {
    m_first_value_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_num_deltas_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_deltas = std::unique_ptr<std::vector<int8_t>>(new std::vector<int8_t>());
    const int l_deltas = num_deltas();
    for (int i = 0; i < l_deltas; i++) {
        m_deltas->push_back(std::move(m__io->read_s1()));
    }
}

dcmp_0_t::chunk_t::extended_body_t::delta_encoding_16_bit_body_t::~delta_encoding_16_bit_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::extended_body_t::delta_encoding_16_bit_body_t::_clean_up() {
}

int32_t dcmp_0_t::chunk_t::extended_body_t::delta_encoding_16_bit_body_t::first_value() {
    if (f_first_value)
        return m_first_value;
    m_first_value = first_value_raw()->value();
    f_first_value = true;
    return m_first_value;
}

int32_t dcmp_0_t::chunk_t::extended_body_t::delta_encoding_16_bit_body_t::num_deltas() {
    if (f_num_deltas)
        return m_num_deltas;
    m_num_deltas = num_deltas_raw()->value();
    f_num_deltas = true;
    return m_num_deltas;
}

dcmp_0_t::chunk_t::extended_body_t::delta_encoding_32_bit_body_t::delta_encoding_32_bit_body_t(kaitai::kstream* p__io, dcmp_0_t::chunk_t::extended_body_t* p__parent, dcmp_0_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_first_value_raw = nullptr;
    m_num_deltas_raw = nullptr;
    m_deltas_raw = nullptr;
    f_first_value = false;
    f_num_deltas = false;
    _read();
}

void dcmp_0_t::chunk_t::extended_body_t::delta_encoding_32_bit_body_t::_read() {
    m_first_value_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_num_deltas_raw = std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io));
    m_deltas_raw = std::unique_ptr<std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>>(new std::vector<std::unique_ptr<dcmp_variable_length_integer_t>>());
    const int l_deltas_raw = num_deltas();
    for (int i = 0; i < l_deltas_raw; i++) {
        m_deltas_raw->push_back(std::move(std::unique_ptr<dcmp_variable_length_integer_t>(new dcmp_variable_length_integer_t(m__io))));
    }
}

dcmp_0_t::chunk_t::extended_body_t::delta_encoding_32_bit_body_t::~delta_encoding_32_bit_body_t() {
    _clean_up();
}

void dcmp_0_t::chunk_t::extended_body_t::delta_encoding_32_bit_body_t::_clean_up() {
}

int32_t dcmp_0_t::chunk_t::extended_body_t::delta_encoding_32_bit_body_t::first_value() {
    if (f_first_value)
        return m_first_value;
    m_first_value = first_value_raw()->value();
    f_first_value = true;
    return m_first_value;
}

int32_t dcmp_0_t::chunk_t::extended_body_t::delta_encoding_32_bit_body_t::num_deltas() {
    if (f_num_deltas)
        return m_num_deltas;
    m_num_deltas = num_deltas_raw()->value();
    f_num_deltas = true;
    return m_num_deltas;
}