#pragma once

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

class broadcom_trx_t;

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>

#if KAITAI_STRUCT_VERSION < 11000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required"
#endif

/**
 * .trx file format is widely used for distribution of firmware
 * updates for Broadcom devices. The most well-known are ASUS routers.
 * 
 * Fundamentally, it includes a footer which acts as a safeguard
 * against installing a firmware package on a wrong hardware model or
 * version, and a header which list numerous partitions packaged inside
 * a single .trx file.
 * 
 * trx files not necessarily contain all these headers.
 * \sa https://github.com/openwrt/firmware-utils/blob/a2c80c5/src/trx.c Source
 * \sa https://web.archive.org/web/20190127154419/https://openwrt.org/docs/techref/header Source
 * \sa https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/mtd/partitions/brcm,trx.txt Source
 */

class broadcom_trx_t : public kaitai::kstruct {

public:
    class header_t;
    class revision_t;
    class tail_t;
    class version_t;

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

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

public:
    ~broadcom_trx_t();

    class header_t : public kaitai::kstruct {

    public:
        class flags_t;
        class partition_t;

        header_t(kaitai::kstream* p__io, broadcom_trx_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

    public:
        ~header_t();

        class flags_t : public kaitai::kstruct {

        public:

            flags_t(kaitai::kstream* p__io, broadcom_trx_t::header_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

        public:
            ~flags_t();

        private:
            std::unique_ptr<std::vector<bool>> m_flags;
            broadcom_trx_t* m__root;
            broadcom_trx_t::header_t* m__parent;

        public:
            std::vector<bool>* flags() const { return m_flags.get(); }
            broadcom_trx_t* _root() const { return m__root; }
            broadcom_trx_t::header_t* _parent() const { return m__parent; }
        };

        class partition_t : public kaitai::kstruct {

        public:

            partition_t(uint8_t p_idx, kaitai::kstream* p__io, broadcom_trx_t::header_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

        public:
            ~partition_t();

        private:
            bool f_body;
            std::string m_body;
            bool n_body;

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

        private:

        public:
            std::string body();

        private:
            bool f_is_last;
            bool m_is_last;
            bool n_is_last;

        public:
            bool _is_null_is_last() { is_last(); return n_is_last; };

        private:

        public:
            bool is_last();

        private:
            bool f_is_present;
            bool m_is_present;

        public:
            bool is_present();

        private:
            bool f_len_body;
            int32_t m_len_body;
            bool n_len_body;

        public:
            bool _is_null_len_body() { len_body(); return n_len_body; };

        private:

        public:
            int32_t len_body();

        private:
            uint32_t m_ofs_body;
            uint8_t m_idx;
            broadcom_trx_t* m__root;
            broadcom_trx_t::header_t* m__parent;

        public:
            uint32_t ofs_body() const { return m_ofs_body; }
            uint8_t idx() const { return m_idx; }
            broadcom_trx_t* _root() const { return m__root; }
            broadcom_trx_t::header_t* _parent() const { return m__parent; }
        };

    private:
        std::string m_magic;
        uint32_t m_len;
        uint32_t m_crc32;
        uint16_t m_version;
        std::unique_ptr<flags_t> m_flags;
        std::unique_ptr<std::vector<std::unique_ptr<partition_t>>> m_partitions;
        broadcom_trx_t* m__root;
        broadcom_trx_t* m__parent;

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

        /**
         * Length of file including header
         */
        uint32_t len() const { return m_len; }

        /**
         * CRC from `version` (??? todo: see the original and disambiguate) to end of file
         */
        uint32_t crc32() const { return m_crc32; }
        uint16_t version() const { return m_version; }
        flags_t* flags() const { return m_flags.get(); }

        /**
         * Offsets of partitions from start of header
         */
        std::vector<std::unique_ptr<partition_t>>* partitions() const { return m_partitions.get(); }
        broadcom_trx_t* _root() const { return m__root; }
        broadcom_trx_t* _parent() const { return m__parent; }
    };

    class revision_t : public kaitai::kstruct {

    public:

        revision_t(kaitai::kstream* p__io, broadcom_trx_t::tail_t::hw_comp_info_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

    public:
        ~revision_t();

    private:
        uint8_t m_major;
        uint8_t m_minor;
        broadcom_trx_t* m__root;
        broadcom_trx_t::tail_t::hw_comp_info_t* m__parent;

    public:
        uint8_t major() const { return m_major; }
        uint8_t minor() const { return m_minor; }
        broadcom_trx_t* _root() const { return m__root; }
        broadcom_trx_t::tail_t::hw_comp_info_t* _parent() const { return m__parent; }
    };

    /**
     * A safeguard against installation of firmware to an incompatible device
     */

    class tail_t : public kaitai::kstruct {

    public:
        class hw_comp_info_t;

        tail_t(kaitai::kstream* p__io, broadcom_trx_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

    public:
        ~tail_t();

        class hw_comp_info_t : public kaitai::kstruct {

        public:

            hw_comp_info_t(kaitai::kstream* p__io, broadcom_trx_t::tail_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

        public:
            ~hw_comp_info_t();

        private:
            std::unique_ptr<revision_t> m_min;
            std::unique_ptr<revision_t> m_max;
            broadcom_trx_t* m__root;
            broadcom_trx_t::tail_t* m__parent;

        public:
            revision_t* min() const { return m_min.get(); }
            revision_t* max() const { return m_max.get(); }
            broadcom_trx_t* _root() const { return m__root; }
            broadcom_trx_t::tail_t* _parent() const { return m__parent; }
        };

    private:
        std::unique_ptr<version_t> m_version;
        std::string m_product_id;
        std::unique_ptr<std::vector<std::unique_ptr<hw_comp_info_t>>> m_comp_hw;
        std::string m_reserved;
        broadcom_trx_t* m__root;
        broadcom_trx_t* m__parent;

    public:

        /**
         * 1.9.2.7 by default
         */
        version_t* version() const { return m_version.get(); }
        std::string product_id() const { return m_product_id; }

        /**
         * 0.02 - 2.99
         */
        std::vector<std::unique_ptr<hw_comp_info_t>>* comp_hw() const { return m_comp_hw.get(); }
        std::string reserved() const { return m_reserved; }
        broadcom_trx_t* _root() const { return m__root; }
        broadcom_trx_t* _parent() const { return m__parent; }
    };

    class version_t : public kaitai::kstruct {

    public:

        version_t(kaitai::kstream* p__io, broadcom_trx_t::tail_t* p__parent = nullptr, broadcom_trx_t* p__root = nullptr);

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

    public:
        ~version_t();

    private:
        uint8_t m_major;
        uint8_t m_minor;
        uint8_t m_patch;
        uint8_t m_tweak;
        broadcom_trx_t* m__root;
        broadcom_trx_t::tail_t* m__parent;

    public:
        uint8_t major() const { return m_major; }
        uint8_t minor() const { return m_minor; }
        uint8_t patch() const { return m_patch; }
        uint8_t tweak() const { return m_tweak; }
        broadcom_trx_t* _root() const { return m__root; }
        broadcom_trx_t::tail_t* _parent() const { return m__parent; }
    };

private:
    bool f_header;
    std::unique_ptr<header_t> m_header;

public:
    header_t* header();

private:
    bool f_tail;
    std::unique_ptr<tail_t> m_tail;

public:
    tail_t* tail();

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

public:
    broadcom_trx_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};
