Mifare Classic RFID tag dump: C++98/STL parsing library

You can get a dump for testing by the link: https://github.com/zhovner/mfdread/raw/master/dump.mfd

File extension

mfd

KS implementation details

License: BSD-2-Clause
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of Mifare Classic RFID tag dump using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++98/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.mfd", 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:
    mifare_classic_t data(&ks);
    

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

data.sectors() // => get sectors

C++98/STL source code to parse Mifare Classic RFID tag dump

mifare_classic.h

#ifndef MIFARE_CLASSIC_H_
#define MIFARE_CLASSIC_H_

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

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

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

/**
 * You can get a dump for testing by the link: https://github.com/zhovner/mfdread/raw/master/dump.mfd
 * \sa https://github.com/nfc-tools/libnfc
 * https://www.nxp.com/docs/en/data-sheet/MF1S70YYX_V1.pdf
 *  Source
 */

class mifare_classic_t : public kaitai::kstruct {

public:
    class key_t;
    class sector_t;
    class manufacturer_t;
    class trailer_t;

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

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

public:
    ~mifare_classic_t();

    class key_t : public kaitai::kstruct {

    public:

        key_t(kaitai::kstream* p__io, mifare_classic_t::trailer_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

    public:
        ~key_t();

    private:
        std::string m_key;
        mifare_classic_t* m__root;
        mifare_classic_t::trailer_t* m__parent;

    public:
        std::string key() const { return m_key; }
        mifare_classic_t* _root() const { return m__root; }
        mifare_classic_t::trailer_t* _parent() const { return m__parent; }
    };

    class sector_t : public kaitai::kstruct {

    public:
        class values_t;
        class filler_t;

        sector_t(bool p_has_manufacturer, kaitai::kstream* p__io, mifare_classic_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

    public:
        ~sector_t();

        class values_t : public kaitai::kstruct {

        public:
            class value_block_t;

            values_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

        public:
            ~values_t();

            class value_block_t : public kaitai::kstruct {

            public:

                value_block_t(kaitai::kstream* p__io, mifare_classic_t::sector_t::values_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

            public:
                ~value_block_t();

            private:
                bool f_addr;
                uint8_t m_addr;
                bool n_addr;

            public:
                bool _is_null_addr() { addr(); return n_addr; };

            private:

            public:
                uint8_t addr();

            private:
                bool f_addr_valid;
                bool m_addr_valid;

            public:
                bool addr_valid();

            private:
                bool f_valid;
                bool m_valid;

            public:
                bool valid();

            private:
                bool f_value_valid;
                bool m_value_valid;

            public:
                bool value_valid();

            private:
                bool f_value;
                uint32_t m_value;
                bool n_value;

            public:
                bool _is_null_value() { value(); return n_value; };

            private:

            public:
                uint32_t value();

            private:
                std::vector<uint32_t>* m_valuez;
                std::vector<uint8_t>* m_addrz;
                mifare_classic_t* m__root;
                mifare_classic_t::sector_t::values_t* m__parent;

            public:
                std::vector<uint32_t>* valuez() const { return m_valuez; }
                std::vector<uint8_t>* addrz() const { return m_addrz; }
                mifare_classic_t* _root() const { return m__root; }
                mifare_classic_t::sector_t::values_t* _parent() const { return m__parent; }
            };

        private:
            std::vector<value_block_t*>* m_values;
            mifare_classic_t* m__root;
            mifare_classic_t::sector_t* m__parent;

        public:
            std::vector<value_block_t*>* values() const { return m_values; }
            mifare_classic_t* _root() const { return m__root; }
            mifare_classic_t::sector_t* _parent() const { return m__parent; }
        };

        /**
         * only to create _io
         */

        class filler_t : public kaitai::kstruct {

        public:

            filler_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

        public:
            ~filler_t();

        private:
            std::string m_data;
            mifare_classic_t* m__root;
            mifare_classic_t::sector_t* m__parent;

        public:
            std::string data() const { return m_data; }
            mifare_classic_t* _root() const { return m__root; }
            mifare_classic_t::sector_t* _parent() const { return m__parent; }
        };

    private:
        bool f_block_size;
        int8_t m_block_size;

    public:
        int8_t block_size();

    private:
        bool f_data;
        std::string m_data;

    public:
        std::string data();

    private:
        bool f_blocks;
        std::vector<std::string>* m_blocks;

    public:
        std::vector<std::string>* blocks();

    private:
        bool f_values;
        values_t* m_values;

    public:
        values_t* values();

    private:
        manufacturer_t* m_manufacturer;
        bool n_manufacturer;

    public:
        bool _is_null_manufacturer() { manufacturer(); return n_manufacturer; };

    private:
        filler_t* m_data_filler;
        trailer_t* m_trailer;
        bool m_has_manufacturer;
        mifare_classic_t* m__root;
        mifare_classic_t* m__parent;
        std::string m__raw_data_filler;
        kaitai::kstream* m__io__raw_data_filler;

    public:
        manufacturer_t* manufacturer() const { return m_manufacturer; }
        filler_t* data_filler() const { return m_data_filler; }
        trailer_t* trailer() const { return m_trailer; }
        bool has_manufacturer() const { return m_has_manufacturer; }
        mifare_classic_t* _root() const { return m__root; }
        mifare_classic_t* _parent() const { return m__parent; }
        std::string _raw_data_filler() const { return m__raw_data_filler; }
        kaitai::kstream* _io__raw_data_filler() const { return m__io__raw_data_filler; }
    };

    class manufacturer_t : public kaitai::kstruct {

    public:

        manufacturer_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

    public:
        ~manufacturer_t();

    private:
        uint32_t m_nuid;
        uint8_t m_bcc;
        uint8_t m_sak;
        uint16_t m_atqa;
        std::string m_manufacturer;
        mifare_classic_t* m__root;
        mifare_classic_t::sector_t* m__parent;

    public:

        /**
         * beware for 7bytes UID it goes over next fields
         */
        uint32_t nuid() const { return m_nuid; }
        uint8_t bcc() const { return m_bcc; }
        uint8_t sak() const { return m_sak; }
        uint16_t atqa() const { return m_atqa; }

        /**
         * may contain manufacture date as BCD
         */
        std::string manufacturer() const { return m_manufacturer; }
        mifare_classic_t* _root() const { return m__root; }
        mifare_classic_t::sector_t* _parent() const { return m__parent; }
    };

    class trailer_t : public kaitai::kstruct {

    public:
        class access_conditions_t;

        trailer_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

    public:
        ~trailer_t();

        class access_conditions_t : public kaitai::kstruct {

        public:
            class trailer_ac_t;
            class chunk_bit_remap_t;
            class data_ac_t;
            class ac_t;
            class valid_chunk_t;

            access_conditions_t(kaitai::kstream* p__io, mifare_classic_t::trailer_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

        public:
            ~access_conditions_t();

            class trailer_ac_t : public kaitai::kstruct {

            public:

                trailer_ac_t(ac_t* p_ac, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

            public:
                ~trailer_ac_t();

            private:
                bool f_can_read_key_b;
                bool m_can_read_key_b;

            public:

                /**
                 * key A is required
                 */
                bool can_read_key_b();

            private:
                bool f_can_write_keys;
                bool m_can_write_keys;

            public:
                bool can_write_keys();

            private:
                bool f_can_write_access_bits;
                bool m_can_write_access_bits;

            public:
                bool can_write_access_bits();

            private:
                bool f_key_b_controls_write;
                bool m_key_b_controls_write;

            public:
                bool key_b_controls_write();

            private:
                ac_t* m_ac;
                mifare_classic_t* m__root;
                mifare_classic_t::trailer_t::access_conditions_t* m__parent;

            public:
                ac_t* ac() const { return m_ac; }
                mifare_classic_t* _root() const { return m__root; }
                mifare_classic_t::trailer_t::access_conditions_t* _parent() const { return m__parent; }
            };

            class chunk_bit_remap_t : public kaitai::kstruct {

            public:

                chunk_bit_remap_t(uint8_t p_bit_no, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

            public:
                ~chunk_bit_remap_t();

            private:
                bool f_shift_value;
                int32_t m_shift_value;

            public:
                int32_t shift_value();

            private:
                bool f_chunk_no;
                int32_t m_chunk_no;

            public:
                int32_t chunk_no();

            private:
                bool f_inv_chunk_no;
                int32_t m_inv_chunk_no;

            public:
                int32_t inv_chunk_no();

            private:
                uint8_t m_bit_no;
                mifare_classic_t* m__root;
                mifare_classic_t::trailer_t::access_conditions_t* m__parent;

            public:
                uint8_t bit_no() const { return m_bit_no; }
                mifare_classic_t* _root() const { return m__root; }
                mifare_classic_t::trailer_t::access_conditions_t* _parent() const { return m__parent; }
            };

            class data_ac_t : public kaitai::kstruct {

            public:

                data_ac_t(ac_t* p_ac, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

            public:
                ~data_ac_t();

            private:
                bool f_read_key_a_required;
                bool m_read_key_a_required;

            public:
                bool read_key_a_required();

            private:
                bool f_write_key_b_required;
                bool m_write_key_b_required;

            public:
                bool write_key_b_required();

            private:
                bool f_write_key_a_required;
                bool m_write_key_a_required;

            public:
                bool write_key_a_required();

            private:
                bool f_read_key_b_required;
                bool m_read_key_b_required;

            public:
                bool read_key_b_required();

            private:
                bool f_decrement_available;
                bool m_decrement_available;

            public:
                bool decrement_available();

            private:
                bool f_increment_available;
                bool m_increment_available;

            public:
                bool increment_available();

            private:
                ac_t* m_ac;
                mifare_classic_t* m__root;
                mifare_classic_t::trailer_t::access_conditions_t* m__parent;

            public:
                ac_t* ac() const { return m_ac; }
                mifare_classic_t* _root() const { return m__root; }
                mifare_classic_t::trailer_t::access_conditions_t* _parent() const { return m__parent; }
            };

            class ac_t : public kaitai::kstruct {

            public:
                class ac_bit_t;

                ac_t(uint8_t p_index, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

            public:
                ~ac_t();

                class ac_bit_t : public kaitai::kstruct {

                public:

                    ac_bit_t(uint8_t p_i, uint8_t p_chunk, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t::ac_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

                public:
                    ~ac_bit_t();

                private:
                    bool f_n;
                    int32_t m_n;

                public:
                    int32_t n();

                private:
                    bool f_b;
                    bool m_b;

                public:
                    bool b();

                private:
                    uint8_t m_i;
                    uint8_t m_chunk;
                    mifare_classic_t* m__root;
                    mifare_classic_t::trailer_t::access_conditions_t::ac_t* m__parent;

                public:
                    uint8_t i() const { return m_i; }
                    uint8_t chunk() const { return m_chunk; }
                    mifare_classic_t* _root() const { return m__root; }
                    mifare_classic_t::trailer_t::access_conditions_t::ac_t* _parent() const { return m__parent; }
                };

            private:
                bool f_bits;
                std::vector<ac_bit_t*>* m_bits;

            public:
                std::vector<ac_bit_t*>* bits();

            private:
                bool f_val;
                int32_t m_val;

            public:

                /**
                 * c3 c2 c1
                 */
                int32_t val();

            private:
                bool f_inv_shift_val;
                int32_t m_inv_shift_val;

            public:
                int32_t inv_shift_val();

            private:
                uint8_t m_index;
                mifare_classic_t* m__root;
                mifare_classic_t::trailer_t::access_conditions_t* m__parent;

            public:
                uint8_t index() const { return m_index; }
                mifare_classic_t* _root() const { return m__root; }
                mifare_classic_t::trailer_t::access_conditions_t* _parent() const { return m__parent; }
            };

            class valid_chunk_t : public kaitai::kstruct {

            public:

                valid_chunk_t(uint8_t p_inv_chunk, uint8_t p_chunk, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent = 0, mifare_classic_t* p__root = 0);

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

            public:
                ~valid_chunk_t();

            private:
                bool f_valid;
                bool m_valid;

            public:
                bool valid();

            private:
                uint8_t m_inv_chunk;
                uint8_t m_chunk;
                mifare_classic_t* m__root;
                mifare_classic_t::trailer_t::access_conditions_t* m__parent;

            public:
                uint8_t inv_chunk() const { return m_inv_chunk; }

                /**
                 * c3 c2 c1 c0
                 */
                uint8_t chunk() const { return m_chunk; }
                mifare_classic_t* _root() const { return m__root; }
                mifare_classic_t::trailer_t::access_conditions_t* _parent() const { return m__parent; }
            };

        private:
            bool f_data_acs;
            std::vector<data_ac_t*>* m_data_acs;

        public:
            std::vector<data_ac_t*>* data_acs();

        private:
            bool f_remaps;
            std::vector<chunk_bit_remap_t*>* m_remaps;

        public:
            std::vector<chunk_bit_remap_t*>* remaps();

        private:
            bool f_acs_raw;
            std::vector<ac_t*>* m_acs_raw;

        public:
            std::vector<ac_t*>* acs_raw();

        private:
            bool f_trailer_ac;
            trailer_ac_t* m_trailer_ac;

        public:
            trailer_ac_t* trailer_ac();

        private:
            bool f_chunks;
            std::vector<valid_chunk_t*>* m_chunks;

        public:
            std::vector<valid_chunk_t*>* chunks();

        private:
            std::vector<uint64_t>* m_raw_chunks;
            mifare_classic_t* m__root;
            mifare_classic_t::trailer_t* m__parent;

        public:
            std::vector<uint64_t>* raw_chunks() const { return m_raw_chunks; }
            mifare_classic_t* _root() const { return m__root; }
            mifare_classic_t::trailer_t* _parent() const { return m__parent; }
        };

    private:
        bool f_ac_bits;
        int8_t m_ac_bits;

    public:
        int8_t ac_bits();

    private:
        bool f_acs_in_sector;
        int8_t m_acs_in_sector;

    public:
        int8_t acs_in_sector();

    private:
        bool f_ac_count_of_chunks;
        int32_t m_ac_count_of_chunks;

    public:
        int32_t ac_count_of_chunks();

    private:
        key_t* m_key_a;
        access_conditions_t* m_access_bits;
        uint8_t m_user_byte;
        key_t* m_key_b;
        mifare_classic_t* m__root;
        mifare_classic_t::sector_t* m__parent;
        std::string m__raw_access_bits;
        kaitai::kstream* m__io__raw_access_bits;

    public:
        key_t* key_a() const { return m_key_a; }
        access_conditions_t* access_bits() const { return m_access_bits; }
        uint8_t user_byte() const { return m_user_byte; }
        key_t* key_b() const { return m_key_b; }
        mifare_classic_t* _root() const { return m__root; }
        mifare_classic_t::sector_t* _parent() const { return m__parent; }
        std::string _raw_access_bits() const { return m__raw_access_bits; }
        kaitai::kstream* _io__raw_access_bits() const { return m__io__raw_access_bits; }
    };

private:
    std::vector<sector_t*>* m_sectors;
    mifare_classic_t* m__root;
    kaitai::kstruct* m__parent;
    std::vector<std::string>* m__raw_sectors;
    std::vector<kaitai::kstream*>* m__io__raw_sectors;

public:
    std::vector<sector_t*>* sectors() const { return m_sectors; }
    mifare_classic_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::vector<std::string>* _raw_sectors() const { return m__raw_sectors; }
    std::vector<kaitai::kstream*>* _io__raw_sectors() const { return m__io__raw_sectors; }
};

#endif  // MIFARE_CLASSIC_H_

mifare_classic.cpp

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

#include "mifare_classic.h"

mifare_classic_t::mifare_classic_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_sectors = 0;
    m__raw_sectors = 0;
    m__io__raw_sectors = 0;

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

void mifare_classic_t::_read() {
    m__raw_sectors = new std::vector<std::string>();
    m__io__raw_sectors = new std::vector<kaitai::kstream*>();
    m_sectors = new std::vector<sector_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m__raw_sectors->push_back(m__io->read_bytes(((((i >= 32) ? (4) : (1)) * 4) * 16)));
            kaitai::kstream* io__raw_sectors = new kaitai::kstream(m__raw_sectors->at(m__raw_sectors->size() - 1));
            m__io__raw_sectors->push_back(io__raw_sectors);
            m_sectors->push_back(new sector_t(i == 0, io__raw_sectors, this, m__root));
            i++;
        }
    }
}

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

void mifare_classic_t::_clean_up() {
    if (m__raw_sectors) {
        delete m__raw_sectors; m__raw_sectors = 0;
    }
    if (m__io__raw_sectors) {
        for (std::vector<kaitai::kstream*>::iterator it = m__io__raw_sectors->begin(); it != m__io__raw_sectors->end(); ++it) {
            delete *it;
        }
        delete m__io__raw_sectors; m__io__raw_sectors = 0;
    }
    if (m_sectors) {
        for (std::vector<sector_t*>::iterator it = m_sectors->begin(); it != m_sectors->end(); ++it) {
            delete *it;
        }
        delete m_sectors; m_sectors = 0;
    }
}

mifare_classic_t::key_t::key_t(kaitai::kstream* p__io, mifare_classic_t::trailer_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void mifare_classic_t::key_t::_read() {
    m_key = m__io->read_bytes(6);
}

mifare_classic_t::key_t::~key_t() {
    _clean_up();
}

void mifare_classic_t::key_t::_clean_up() {
}

mifare_classic_t::sector_t::sector_t(bool p_has_manufacturer, kaitai::kstream* p__io, mifare_classic_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_has_manufacturer = p_has_manufacturer;
    m_manufacturer = 0;
    m_data_filler = 0;
    m__io__raw_data_filler = 0;
    m_trailer = 0;
    m_blocks = 0;
    m_values = 0;
    f_block_size = false;
    f_data = false;
    f_blocks = false;
    f_values = false;

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

void mifare_classic_t::sector_t::_read() {
    n_manufacturer = true;
    if (has_manufacturer()) {
        n_manufacturer = false;
        m_manufacturer = new manufacturer_t(m__io, this, m__root);
    }
    m__raw_data_filler = m__io->read_bytes(((_io()->size() - _io()->pos()) - 16));
    m__io__raw_data_filler = new kaitai::kstream(m__raw_data_filler);
    m_data_filler = new filler_t(m__io__raw_data_filler, this, m__root);
    m_trailer = new trailer_t(m__io, this, m__root);
}

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

void mifare_classic_t::sector_t::_clean_up() {
    if (!n_manufacturer) {
        if (m_manufacturer) {
            delete m_manufacturer; m_manufacturer = 0;
        }
    }
    if (m__io__raw_data_filler) {
        delete m__io__raw_data_filler; m__io__raw_data_filler = 0;
    }
    if (m_data_filler) {
        delete m_data_filler; m_data_filler = 0;
    }
    if (m_trailer) {
        delete m_trailer; m_trailer = 0;
    }
    if (f_blocks) {
        if (m_blocks) {
            delete m_blocks; m_blocks = 0;
        }
    }
    if (f_values) {
        if (m_values) {
            delete m_values; m_values = 0;
        }
    }
}

mifare_classic_t::sector_t::values_t::values_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_values = 0;

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

void mifare_classic_t::sector_t::values_t::_read() {
    m_values = new std::vector<value_block_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_values->push_back(new value_block_t(m__io, this, m__root));
            i++;
        }
    }
}

mifare_classic_t::sector_t::values_t::~values_t() {
    _clean_up();
}

void mifare_classic_t::sector_t::values_t::_clean_up() {
    if (m_values) {
        for (std::vector<value_block_t*>::iterator it = m_values->begin(); it != m_values->end(); ++it) {
            delete *it;
        }
        delete m_values; m_values = 0;
    }
}

mifare_classic_t::sector_t::values_t::value_block_t::value_block_t(kaitai::kstream* p__io, mifare_classic_t::sector_t::values_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_valuez = 0;
    m_addrz = 0;
    f_addr = false;
    f_addr_valid = false;
    f_valid = false;
    f_value_valid = false;
    f_value = false;

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

void mifare_classic_t::sector_t::values_t::value_block_t::_read() {
    int l_valuez = 3;
    m_valuez = new std::vector<uint32_t>();
    m_valuez->reserve(l_valuez);
    for (int i = 0; i < l_valuez; i++) {
        m_valuez->push_back(m__io->read_u4le());
    }
    int l_addrz = 4;
    m_addrz = new std::vector<uint8_t>();
    m_addrz->reserve(l_addrz);
    for (int i = 0; i < l_addrz; i++) {
        m_addrz->push_back(m__io->read_u1());
    }
}

mifare_classic_t::sector_t::values_t::value_block_t::~value_block_t() {
    _clean_up();
}

void mifare_classic_t::sector_t::values_t::value_block_t::_clean_up() {
    if (m_valuez) {
        delete m_valuez; m_valuez = 0;
    }
    if (m_addrz) {
        delete m_addrz; m_addrz = 0;
    }
}

uint8_t mifare_classic_t::sector_t::values_t::value_block_t::addr() {
    if (f_addr)
        return m_addr;
    n_addr = true;
    if (valid()) {
        n_addr = false;
        m_addr = addrz()->at(0);
    }
    f_addr = true;
    return m_addr;
}

bool mifare_classic_t::sector_t::values_t::value_block_t::addr_valid() {
    if (f_addr_valid)
        return m_addr_valid;
    m_addr_valid =  ((addrz()->at(0) == ~(addrz()->at(1))) && (addrz()->at(0) == addrz()->at(2)) && (addrz()->at(1) == addrz()->at(3))) ;
    f_addr_valid = true;
    return m_addr_valid;
}

bool mifare_classic_t::sector_t::values_t::value_block_t::valid() {
    if (f_valid)
        return m_valid;
    m_valid =  ((value_valid()) && (addr_valid())) ;
    f_valid = true;
    return m_valid;
}

bool mifare_classic_t::sector_t::values_t::value_block_t::value_valid() {
    if (f_value_valid)
        return m_value_valid;
    m_value_valid =  ((valuez()->at(0) == ~(valuez()->at(1))) && (valuez()->at(0) == valuez()->at(2))) ;
    f_value_valid = true;
    return m_value_valid;
}

uint32_t mifare_classic_t::sector_t::values_t::value_block_t::value() {
    if (f_value)
        return m_value;
    n_value = true;
    if (valid()) {
        n_value = false;
        m_value = valuez()->at(0);
    }
    f_value = true;
    return m_value;
}

mifare_classic_t::sector_t::filler_t::filler_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void mifare_classic_t::sector_t::filler_t::_read() {
    m_data = m__io->read_bytes(_io()->size());
}

mifare_classic_t::sector_t::filler_t::~filler_t() {
    _clean_up();
}

void mifare_classic_t::sector_t::filler_t::_clean_up() {
}

int8_t mifare_classic_t::sector_t::block_size() {
    if (f_block_size)
        return m_block_size;
    m_block_size = 16;
    f_block_size = true;
    return m_block_size;
}

std::string mifare_classic_t::sector_t::data() {
    if (f_data)
        return m_data;
    m_data = data_filler()->data();
    f_data = true;
    return m_data;
}

std::vector<std::string>* mifare_classic_t::sector_t::blocks() {
    if (f_blocks)
        return m_blocks;
    kaitai::kstream *io = data_filler()->_io();
    std::streampos _pos = io->pos();
    io->seek(0);
    m_blocks = new std::vector<std::string>();
    {
        int i = 0;
        while (!io->is_eof()) {
            m_blocks->push_back(io->read_bytes(block_size()));
            i++;
        }
    }
    io->seek(_pos);
    f_blocks = true;
    return m_blocks;
}

mifare_classic_t::sector_t::values_t* mifare_classic_t::sector_t::values() {
    if (f_values)
        return m_values;
    kaitai::kstream *io = data_filler()->_io();
    std::streampos _pos = io->pos();
    io->seek(0);
    m_values = new values_t(io, this, m__root);
    io->seek(_pos);
    f_values = true;
    return m_values;
}

mifare_classic_t::manufacturer_t::manufacturer_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

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

void mifare_classic_t::manufacturer_t::_read() {
    m_nuid = m__io->read_u4le();
    m_bcc = m__io->read_u1();
    m_sak = m__io->read_u1();
    m_atqa = m__io->read_u2le();
    m_manufacturer = m__io->read_bytes(8);
}

mifare_classic_t::manufacturer_t::~manufacturer_t() {
    _clean_up();
}

void mifare_classic_t::manufacturer_t::_clean_up() {
}

mifare_classic_t::trailer_t::trailer_t(kaitai::kstream* p__io, mifare_classic_t::sector_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_key_a = 0;
    m_access_bits = 0;
    m__io__raw_access_bits = 0;
    m_key_b = 0;
    f_ac_bits = false;
    f_acs_in_sector = false;
    f_ac_count_of_chunks = false;

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

void mifare_classic_t::trailer_t::_read() {
    m_key_a = new key_t(m__io, this, m__root);
    m__raw_access_bits = m__io->read_bytes(3);
    m__io__raw_access_bits = new kaitai::kstream(m__raw_access_bits);
    m_access_bits = new access_conditions_t(m__io__raw_access_bits, this, m__root);
    m_user_byte = m__io->read_u1();
    m_key_b = new key_t(m__io, this, m__root);
}

mifare_classic_t::trailer_t::~trailer_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::_clean_up() {
    if (m_key_a) {
        delete m_key_a; m_key_a = 0;
    }
    if (m__io__raw_access_bits) {
        delete m__io__raw_access_bits; m__io__raw_access_bits = 0;
    }
    if (m_access_bits) {
        delete m_access_bits; m_access_bits = 0;
    }
    if (m_key_b) {
        delete m_key_b; m_key_b = 0;
    }
}

mifare_classic_t::trailer_t::access_conditions_t::access_conditions_t(kaitai::kstream* p__io, mifare_classic_t::trailer_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_raw_chunks = 0;
    m_data_acs = 0;
    m_remaps = 0;
    m_acs_raw = 0;
    m_trailer_ac = 0;
    m_chunks = 0;
    f_data_acs = false;
    f_remaps = false;
    f_acs_raw = false;
    f_trailer_ac = false;
    f_chunks = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::_read() {
    int l_raw_chunks = _parent()->ac_count_of_chunks();
    m_raw_chunks = new std::vector<uint64_t>();
    m_raw_chunks->reserve(l_raw_chunks);
    for (int i = 0; i < l_raw_chunks; i++) {
        m_raw_chunks->push_back(m__io->read_bits_int_be(4));
    }
}

mifare_classic_t::trailer_t::access_conditions_t::~access_conditions_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::_clean_up() {
    if (m_raw_chunks) {
        delete m_raw_chunks; m_raw_chunks = 0;
    }
    if (f_data_acs) {
        if (m_data_acs) {
            for (std::vector<data_ac_t*>::iterator it = m_data_acs->begin(); it != m_data_acs->end(); ++it) {
                delete *it;
            }
            delete m_data_acs; m_data_acs = 0;
        }
    }
    if (f_remaps) {
        if (m_remaps) {
            for (std::vector<chunk_bit_remap_t*>::iterator it = m_remaps->begin(); it != m_remaps->end(); ++it) {
                delete *it;
            }
            delete m_remaps; m_remaps = 0;
        }
    }
    if (f_acs_raw) {
        if (m_acs_raw) {
            for (std::vector<ac_t*>::iterator it = m_acs_raw->begin(); it != m_acs_raw->end(); ++it) {
                delete *it;
            }
            delete m_acs_raw; m_acs_raw = 0;
        }
    }
    if (f_trailer_ac) {
        if (m_trailer_ac) {
            delete m_trailer_ac; m_trailer_ac = 0;
        }
    }
    if (f_chunks) {
        if (m_chunks) {
            for (std::vector<valid_chunk_t*>::iterator it = m_chunks->begin(); it != m_chunks->end(); ++it) {
                delete *it;
            }
            delete m_chunks; m_chunks = 0;
        }
    }
}

mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::trailer_ac_t(ac_t* p_ac, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_ac = p_ac;
    f_can_read_key_b = false;
    f_can_write_keys = false;
    f_can_write_access_bits = false;
    f_key_b_controls_write = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::_read() {
}

mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::~trailer_ac_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::_clean_up() {
}

bool mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::can_read_key_b() {
    if (f_can_read_key_b)
        return m_can_read_key_b;
    m_can_read_key_b = ac()->inv_shift_val() <= 2;
    f_can_read_key_b = true;
    return m_can_read_key_b;
}

bool mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::can_write_keys() {
    if (f_can_write_keys)
        return m_can_write_keys;
    m_can_write_keys =  ((kaitai::kstream::mod((ac()->inv_shift_val() + 1), 3) != 0) && (ac()->inv_shift_val() < 6)) ;
    f_can_write_keys = true;
    return m_can_write_keys;
}

bool mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::can_write_access_bits() {
    if (f_can_write_access_bits)
        return m_can_write_access_bits;
    m_can_write_access_bits = ac()->bits()->at(2)->b();
    f_can_write_access_bits = true;
    return m_can_write_access_bits;
}

bool mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t::key_b_controls_write() {
    if (f_key_b_controls_write)
        return m_key_b_controls_write;
    m_key_b_controls_write = !(can_read_key_b());
    f_key_b_controls_write = true;
    return m_key_b_controls_write;
}

mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::chunk_bit_remap_t(uint8_t p_bit_no, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_bit_no = p_bit_no;
    f_shift_value = false;
    f_chunk_no = false;
    f_inv_chunk_no = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::_read() {
}

mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::~chunk_bit_remap_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::_clean_up() {
}

int32_t mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::shift_value() {
    if (f_shift_value)
        return m_shift_value;
    m_shift_value = ((bit_no() == 1) ? (-1) : (1));
    f_shift_value = true;
    return m_shift_value;
}

int32_t mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::chunk_no() {
    if (f_chunk_no)
        return m_chunk_no;
    m_chunk_no = kaitai::kstream::mod(((inv_chunk_no() + shift_value()) + _parent()->_parent()->ac_count_of_chunks()), _parent()->_parent()->ac_count_of_chunks());
    f_chunk_no = true;
    return m_chunk_no;
}

int32_t mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t::inv_chunk_no() {
    if (f_inv_chunk_no)
        return m_inv_chunk_no;
    m_inv_chunk_no = (bit_no() + shift_value());
    f_inv_chunk_no = true;
    return m_inv_chunk_no;
}

mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::data_ac_t(ac_t* p_ac, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_ac = p_ac;
    f_read_key_a_required = false;
    f_write_key_b_required = false;
    f_write_key_a_required = false;
    f_read_key_b_required = false;
    f_decrement_available = false;
    f_increment_available = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::_read() {
}

mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::~data_ac_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::_clean_up() {
}

bool mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::read_key_a_required() {
    if (f_read_key_a_required)
        return m_read_key_a_required;
    m_read_key_a_required = ac()->val() <= 4;
    f_read_key_a_required = true;
    return m_read_key_a_required;
}

bool mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::write_key_b_required() {
    if (f_write_key_b_required)
        return m_write_key_b_required;
    m_write_key_b_required =  (( ((!(read_key_a_required())) || (read_key_b_required())) ) && (!(ac()->bits()->at(0)->b()))) ;
    f_write_key_b_required = true;
    return m_write_key_b_required;
}

bool mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::write_key_a_required() {
    if (f_write_key_a_required)
        return m_write_key_a_required;
    m_write_key_a_required = ac()->val() == 0;
    f_write_key_a_required = true;
    return m_write_key_a_required;
}

bool mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::read_key_b_required() {
    if (f_read_key_b_required)
        return m_read_key_b_required;
    m_read_key_b_required = ac()->val() <= 6;
    f_read_key_b_required = true;
    return m_read_key_b_required;
}

bool mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::decrement_available() {
    if (f_decrement_available)
        return m_decrement_available;
    m_decrement_available =  (( ((ac()->bits()->at(1)->b()) || (!(ac()->bits()->at(0)->b()))) ) && (!(ac()->bits()->at(2)->b()))) ;
    f_decrement_available = true;
    return m_decrement_available;
}

bool mifare_classic_t::trailer_t::access_conditions_t::data_ac_t::increment_available() {
    if (f_increment_available)
        return m_increment_available;
    m_increment_available =  (( ((!(ac()->bits()->at(0)->b())) && (!(read_key_a_required())) && (!(read_key_b_required()))) ) || ( ((!(ac()->bits()->at(0)->b())) && (read_key_a_required()) && (read_key_b_required())) )) ;
    f_increment_available = true;
    return m_increment_available;
}

mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_t(uint8_t p_index, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_index = p_index;
    m_bits = 0;
    f_bits = false;
    f_val = false;
    f_inv_shift_val = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::ac_t::_read() {
}

mifare_classic_t::trailer_t::access_conditions_t::ac_t::~ac_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::ac_t::_clean_up() {
    if (f_bits) {
        if (m_bits) {
            for (std::vector<ac_bit_t*>::iterator it = m_bits->begin(); it != m_bits->end(); ++it) {
                delete *it;
            }
            delete m_bits; m_bits = 0;
        }
    }
}

mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t::ac_bit_t(uint8_t p_i, uint8_t p_chunk, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t::ac_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_i = p_i;
    m_chunk = p_chunk;
    f_n = false;
    f_b = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t::_read() {
}

mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t::~ac_bit_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t::_clean_up() {
}

int32_t mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t::n() {
    if (f_n)
        return m_n;
    m_n = ((chunk() >> i()) & 1);
    f_n = true;
    return m_n;
}

bool mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t::b() {
    if (f_b)
        return m_b;
    m_b = n() == 1;
    f_b = true;
    return m_b;
}

std::vector<mifare_classic_t::trailer_t::access_conditions_t::ac_t::ac_bit_t*>* mifare_classic_t::trailer_t::access_conditions_t::ac_t::bits() {
    if (f_bits)
        return m_bits;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    int l_bits = _parent()->_parent()->ac_bits();
    m_bits = new std::vector<ac_bit_t*>();
    m_bits->reserve(l_bits);
    for (int i = 0; i < l_bits; i++) {
        m_bits->push_back(new ac_bit_t(index(), _parent()->chunks()->at(i)->chunk(), m__io, this, m__root));
    }
    m__io->seek(_pos);
    f_bits = true;
    return m_bits;
}

int32_t mifare_classic_t::trailer_t::access_conditions_t::ac_t::val() {
    if (f_val)
        return m_val;
    m_val = (((bits()->at(2)->n() << 2) | (bits()->at(1)->n() << 1)) | bits()->at(0)->n());
    f_val = true;
    return m_val;
}

int32_t mifare_classic_t::trailer_t::access_conditions_t::ac_t::inv_shift_val() {
    if (f_inv_shift_val)
        return m_inv_shift_val;
    m_inv_shift_val = (((bits()->at(0)->n() << 2) | (bits()->at(1)->n() << 1)) | bits()->at(2)->n());
    f_inv_shift_val = true;
    return m_inv_shift_val;
}

mifare_classic_t::trailer_t::access_conditions_t::valid_chunk_t::valid_chunk_t(uint8_t p_inv_chunk, uint8_t p_chunk, kaitai::kstream* p__io, mifare_classic_t::trailer_t::access_conditions_t* p__parent, mifare_classic_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_inv_chunk = p_inv_chunk;
    m_chunk = p_chunk;
    f_valid = false;

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

void mifare_classic_t::trailer_t::access_conditions_t::valid_chunk_t::_read() {
}

mifare_classic_t::trailer_t::access_conditions_t::valid_chunk_t::~valid_chunk_t() {
    _clean_up();
}

void mifare_classic_t::trailer_t::access_conditions_t::valid_chunk_t::_clean_up() {
}

bool mifare_classic_t::trailer_t::access_conditions_t::valid_chunk_t::valid() {
    if (f_valid)
        return m_valid;
    m_valid = (inv_chunk() ^ chunk()) == 15;
    f_valid = true;
    return m_valid;
}

std::vector<mifare_classic_t::trailer_t::access_conditions_t::data_ac_t*>* mifare_classic_t::trailer_t::access_conditions_t::data_acs() {
    if (f_data_acs)
        return m_data_acs;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    int l_data_acs = (_parent()->acs_in_sector() - 1);
    m_data_acs = new std::vector<data_ac_t*>();
    m_data_acs->reserve(l_data_acs);
    for (int i = 0; i < l_data_acs; i++) {
        m_data_acs->push_back(new data_ac_t(acs_raw()->at(i), m__io, this, m__root));
    }
    m__io->seek(_pos);
    f_data_acs = true;
    return m_data_acs;
}

std::vector<mifare_classic_t::trailer_t::access_conditions_t::chunk_bit_remap_t*>* mifare_classic_t::trailer_t::access_conditions_t::remaps() {
    if (f_remaps)
        return m_remaps;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    int l_remaps = _parent()->ac_bits();
    m_remaps = new std::vector<chunk_bit_remap_t*>();
    m_remaps->reserve(l_remaps);
    for (int i = 0; i < l_remaps; i++) {
        m_remaps->push_back(new chunk_bit_remap_t(i, m__io, this, m__root));
    }
    m__io->seek(_pos);
    f_remaps = true;
    return m_remaps;
}

std::vector<mifare_classic_t::trailer_t::access_conditions_t::ac_t*>* mifare_classic_t::trailer_t::access_conditions_t::acs_raw() {
    if (f_acs_raw)
        return m_acs_raw;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    int l_acs_raw = _parent()->acs_in_sector();
    m_acs_raw = new std::vector<ac_t*>();
    m_acs_raw->reserve(l_acs_raw);
    for (int i = 0; i < l_acs_raw; i++) {
        m_acs_raw->push_back(new ac_t(i, m__io, this, m__root));
    }
    m__io->seek(_pos);
    f_acs_raw = true;
    return m_acs_raw;
}

mifare_classic_t::trailer_t::access_conditions_t::trailer_ac_t* mifare_classic_t::trailer_t::access_conditions_t::trailer_ac() {
    if (f_trailer_ac)
        return m_trailer_ac;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    m_trailer_ac = new trailer_ac_t(acs_raw()->at((_parent()->acs_in_sector() - 1)), m__io, this, m__root);
    m__io->seek(_pos);
    f_trailer_ac = true;
    return m_trailer_ac;
}

std::vector<mifare_classic_t::trailer_t::access_conditions_t::valid_chunk_t*>* mifare_classic_t::trailer_t::access_conditions_t::chunks() {
    if (f_chunks)
        return m_chunks;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    int l_chunks = _parent()->ac_bits();
    m_chunks = new std::vector<valid_chunk_t*>();
    m_chunks->reserve(l_chunks);
    for (int i = 0; i < l_chunks; i++) {
        m_chunks->push_back(new valid_chunk_t(raw_chunks()->at(remaps()->at(i)->inv_chunk_no()), raw_chunks()->at(remaps()->at(i)->chunk_no()), m__io, this, m__root));
    }
    m__io->seek(_pos);
    f_chunks = true;
    return m_chunks;
}

int8_t mifare_classic_t::trailer_t::ac_bits() {
    if (f_ac_bits)
        return m_ac_bits;
    m_ac_bits = 3;
    f_ac_bits = true;
    return m_ac_bits;
}

int8_t mifare_classic_t::trailer_t::acs_in_sector() {
    if (f_acs_in_sector)
        return m_acs_in_sector;
    m_acs_in_sector = 4;
    f_acs_in_sector = true;
    return m_acs_in_sector;
}

int32_t mifare_classic_t::trailer_t::ac_count_of_chunks() {
    if (f_ac_count_of_chunks)
        return m_ac_count_of_chunks;
    m_ac_count_of_chunks = (ac_bits() * 2);
    f_ac_count_of_chunks = true;
    return m_ac_count_of_chunks;
}