ID3v2.4 tag for .mp3 files: C++11/STL parsing library

File extension

mp3

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of ID3v2.4 tag for .mp3 files 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.mp3", 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:
    id3v2_4_t data(&ks);
    

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

data.tag() // => get tag

C++11/STL source code to parse ID3v2.4 tag for .mp3 files

id3v2_4.h

#pragma once

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

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

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

/**
 * \sa http://id3.org/id3v2.4.0-structure Source
 * \sa http://id3.org/id3v2.4.0-frames Source
 */

class id3v2_4_t : public kaitai::kstruct {

public:
    class u1be_synchsafe_t;
    class u2be_synchsafe_t;
    class tag_t;
    class u4be_synchsafe_t;
    class frame_t;
    class header_ex_t;
    class header_t;
    class padding_t;
    class footer_t;

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

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

public:
    ~id3v2_4_t();

    class u1be_synchsafe_t : public kaitai::kstruct {

    public:

        u1be_synchsafe_t(kaitai::kstream* p__io, id3v2_4_t::u2be_synchsafe_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~u1be_synchsafe_t();

    private:
        bool m_padding;
        uint64_t m_value;
        id3v2_4_t* m__root;
        id3v2_4_t::u2be_synchsafe_t* m__parent;

    public:
        bool padding() const { return m_padding; }
        uint64_t value() const { return m_value; }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::u2be_synchsafe_t* _parent() const { return m__parent; }
    };

    class u2be_synchsafe_t : public kaitai::kstruct {

    public:

        u2be_synchsafe_t(kaitai::kstream* p__io, id3v2_4_t::u4be_synchsafe_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~u2be_synchsafe_t();

    private:
        bool f_value;
        int32_t m_value;

    public:
        int32_t value();

    private:
        std::unique_ptr<u1be_synchsafe_t> m_byte0;
        std::unique_ptr<u1be_synchsafe_t> m_byte1;
        id3v2_4_t* m__root;
        id3v2_4_t::u4be_synchsafe_t* m__parent;

    public:
        u1be_synchsafe_t* byte0() const { return m_byte0.get(); }
        u1be_synchsafe_t* byte1() const { return m_byte1.get(); }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::u4be_synchsafe_t* _parent() const { return m__parent; }
    };

    class tag_t : public kaitai::kstruct {

    public:

        tag_t(kaitai::kstream* p__io, id3v2_4_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~tag_t();

    private:
        std::unique_ptr<header_t> m_header;
        std::unique_ptr<header_ex_t> m_header_ex;
        bool n_header_ex;

    public:
        bool _is_null_header_ex() { header_ex(); return n_header_ex; };

    private:
        std::unique_ptr<std::vector<std::unique_ptr<frame_t>>> m_frames;
        std::unique_ptr<padding_t> m_padding;
        bool n_padding;

    public:
        bool _is_null_padding() { padding(); return n_padding; };

    private:
        std::unique_ptr<footer_t> m_footer;
        bool n_footer;

    public:
        bool _is_null_footer() { footer(); return n_footer; };

    private:
        id3v2_4_t* m__root;
        id3v2_4_t* m__parent;

    public:
        header_t* header() const { return m_header.get(); }
        header_ex_t* header_ex() const { return m_header_ex.get(); }
        std::vector<std::unique_ptr<frame_t>>* frames() const { return m_frames.get(); }
        padding_t* padding() const { return m_padding.get(); }
        footer_t* footer() const { return m_footer.get(); }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t* _parent() const { return m__parent; }
    };

    class u4be_synchsafe_t : public kaitai::kstruct {

    public:

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

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

    public:
        ~u4be_synchsafe_t();

    private:
        bool f_value;
        int32_t m_value;

    public:
        int32_t value();

    private:
        std::unique_ptr<u2be_synchsafe_t> m_short0;
        std::unique_ptr<u2be_synchsafe_t> m_short1;
        id3v2_4_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        u2be_synchsafe_t* short0() const { return m_short0.get(); }
        u2be_synchsafe_t* short1() const { return m_short1.get(); }
        id3v2_4_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class frame_t : public kaitai::kstruct {

    public:
        class flags_status_t;
        class flags_format_t;

        frame_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~frame_t();

        class flags_status_t : public kaitai::kstruct {

        public:

            flags_status_t(kaitai::kstream* p__io, id3v2_4_t::frame_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

        public:
            ~flags_status_t();

        private:
            bool m_reserved1;
            bool m_flag_discard_alter_tag;
            bool m_flag_discard_alter_file;
            bool m_flag_read_only;
            uint64_t m_reserved2;
            id3v2_4_t* m__root;
            id3v2_4_t::frame_t* m__parent;

        public:
            bool reserved1() const { return m_reserved1; }
            bool flag_discard_alter_tag() const { return m_flag_discard_alter_tag; }
            bool flag_discard_alter_file() const { return m_flag_discard_alter_file; }
            bool flag_read_only() const { return m_flag_read_only; }
            uint64_t reserved2() const { return m_reserved2; }
            id3v2_4_t* _root() const { return m__root; }
            id3v2_4_t::frame_t* _parent() const { return m__parent; }
        };

        class flags_format_t : public kaitai::kstruct {

        public:

            flags_format_t(kaitai::kstream* p__io, id3v2_4_t::frame_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

        public:
            ~flags_format_t();

        private:
            bool m_reserved1;
            bool m_flag_grouping;
            uint64_t m_reserved2;
            bool m_flag_compressed;
            bool m_flag_encrypted;
            bool m_flag_unsynchronisated;
            bool m_flag_indicator;
            id3v2_4_t* m__root;
            id3v2_4_t::frame_t* m__parent;

        public:
            bool reserved1() const { return m_reserved1; }
            bool flag_grouping() const { return m_flag_grouping; }
            uint64_t reserved2() const { return m_reserved2; }
            bool flag_compressed() const { return m_flag_compressed; }
            bool flag_encrypted() const { return m_flag_encrypted; }
            bool flag_unsynchronisated() const { return m_flag_unsynchronisated; }
            bool flag_indicator() const { return m_flag_indicator; }
            id3v2_4_t* _root() const { return m__root; }
            id3v2_4_t::frame_t* _parent() const { return m__parent; }
        };

    private:
        bool f_is_invalid;
        bool m_is_invalid;

    public:
        bool is_invalid();

    private:
        std::string m_id;
        std::unique_ptr<u4be_synchsafe_t> m_size;
        std::unique_ptr<flags_status_t> m_flags_status;
        std::unique_ptr<flags_format_t> m_flags_format;
        std::string m_data;
        id3v2_4_t* m__root;
        id3v2_4_t::tag_t* m__parent;

    public:
        std::string id() const { return m_id; }
        u4be_synchsafe_t* size() const { return m_size.get(); }
        flags_status_t* flags_status() const { return m_flags_status.get(); }
        flags_format_t* flags_format() const { return m_flags_format.get(); }
        std::string data() const { return m_data; }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::tag_t* _parent() const { return m__parent; }
    };

    class header_ex_t : public kaitai::kstruct {

    public:
        class flags_ex_t;

        header_ex_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~header_ex_t();

        class flags_ex_t : public kaitai::kstruct {

        public:

            flags_ex_t(kaitai::kstream* p__io, id3v2_4_t::header_ex_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

        public:
            ~flags_ex_t();

        private:
            bool m_reserved1;
            bool m_flag_update;
            bool m_flag_crc;
            bool m_flag_restrictions;
            uint64_t m_reserved2;
            id3v2_4_t* m__root;
            id3v2_4_t::header_ex_t* m__parent;

        public:
            bool reserved1() const { return m_reserved1; }
            bool flag_update() const { return m_flag_update; }
            bool flag_crc() const { return m_flag_crc; }
            bool flag_restrictions() const { return m_flag_restrictions; }
            uint64_t reserved2() const { return m_reserved2; }
            id3v2_4_t* _root() const { return m__root; }
            id3v2_4_t::header_ex_t* _parent() const { return m__parent; }
        };

    private:
        std::unique_ptr<u4be_synchsafe_t> m_size;
        std::unique_ptr<flags_ex_t> m_flags_ex;
        std::string m_data;
        id3v2_4_t* m__root;
        id3v2_4_t::tag_t* m__parent;

    public:
        u4be_synchsafe_t* size() const { return m_size.get(); }
        flags_ex_t* flags_ex() const { return m_flags_ex.get(); }
        std::string data() const { return m_data; }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::tag_t* _parent() const { return m__parent; }
    };

    class header_t : public kaitai::kstruct {

    public:
        class flags_t;

        header_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent = nullptr, id3v2_4_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, id3v2_4_t::header_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

        public:
            ~flags_t();

        private:
            bool m_flag_unsynchronization;
            bool m_flag_headerex;
            bool m_flag_experimental;
            bool m_flag_footer;
            uint64_t m_reserved;
            id3v2_4_t* m__root;
            id3v2_4_t::header_t* m__parent;

        public:
            bool flag_unsynchronization() const { return m_flag_unsynchronization; }
            bool flag_headerex() const { return m_flag_headerex; }
            bool flag_experimental() const { return m_flag_experimental; }
            bool flag_footer() const { return m_flag_footer; }
            uint64_t reserved() const { return m_reserved; }
            id3v2_4_t* _root() const { return m__root; }
            id3v2_4_t::header_t* _parent() const { return m__parent; }
        };

    private:
        std::string m_magic;
        uint8_t m_version_major;
        uint8_t m_version_revision;
        std::unique_ptr<flags_t> m_flags;
        std::unique_ptr<u4be_synchsafe_t> m_size;
        id3v2_4_t* m__root;
        id3v2_4_t::tag_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint8_t version_major() const { return m_version_major; }
        uint8_t version_revision() const { return m_version_revision; }
        flags_t* flags() const { return m_flags.get(); }
        u4be_synchsafe_t* size() const { return m_size.get(); }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::tag_t* _parent() const { return m__parent; }
    };

    class padding_t : public kaitai::kstruct {

    public:

        padding_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~padding_t();

    private:
        std::string m_padding;
        id3v2_4_t* m__root;
        id3v2_4_t::tag_t* m__parent;

    public:
        std::string padding() const { return m_padding; }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::tag_t* _parent() const { return m__parent; }
    };

    class footer_t : public kaitai::kstruct {

    public:
        class flags_t;

        footer_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

    public:
        ~footer_t();

        class flags_t : public kaitai::kstruct {

        public:

            flags_t(kaitai::kstream* p__io, id3v2_4_t::footer_t* p__parent = nullptr, id3v2_4_t* p__root = nullptr);

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

        public:
            ~flags_t();

        private:
            bool m_flag_unsynchronization;
            bool m_flag_headerex;
            bool m_flag_experimental;
            bool m_flag_footer;
            uint64_t m_reserved;
            id3v2_4_t* m__root;
            id3v2_4_t::footer_t* m__parent;

        public:
            bool flag_unsynchronization() const { return m_flag_unsynchronization; }
            bool flag_headerex() const { return m_flag_headerex; }
            bool flag_experimental() const { return m_flag_experimental; }
            bool flag_footer() const { return m_flag_footer; }
            uint64_t reserved() const { return m_reserved; }
            id3v2_4_t* _root() const { return m__root; }
            id3v2_4_t::footer_t* _parent() const { return m__parent; }
        };

    private:
        std::string m_magic;
        uint8_t m_version_major;
        uint8_t m_version_revision;
        std::unique_ptr<flags_t> m_flags;
        std::unique_ptr<u4be_synchsafe_t> m_size;
        id3v2_4_t* m__root;
        id3v2_4_t::tag_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint8_t version_major() const { return m_version_major; }
        uint8_t version_revision() const { return m_version_revision; }
        flags_t* flags() const { return m_flags.get(); }
        u4be_synchsafe_t* size() const { return m_size.get(); }
        id3v2_4_t* _root() const { return m__root; }
        id3v2_4_t::tag_t* _parent() const { return m__parent; }
    };

private:
    std::unique_ptr<tag_t> m_tag;
    id3v2_4_t* m__root;
    kaitai::kstruct* m__parent;

public:
    tag_t* tag() const { return m_tag.get(); }
    id3v2_4_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

id3v2_4.cpp

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

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

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

void id3v2_4_t::_read() {
    m_tag = std::unique_ptr<tag_t>(new tag_t(m__io, this, m__root));
}

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

void id3v2_4_t::_clean_up() {
}

id3v2_4_t::u1be_synchsafe_t::u1be_synchsafe_t(kaitai::kstream* p__io, id3v2_4_t::u2be_synchsafe_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::u1be_synchsafe_t::_read() {
    m_padding = m__io->read_bits_int_be(1);
    m_value = m__io->read_bits_int_be(7);
}

id3v2_4_t::u1be_synchsafe_t::~u1be_synchsafe_t() {
    _clean_up();
}

void id3v2_4_t::u1be_synchsafe_t::_clean_up() {
}

id3v2_4_t::u2be_synchsafe_t::u2be_synchsafe_t(kaitai::kstream* p__io, id3v2_4_t::u4be_synchsafe_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_byte0 = nullptr;
    m_byte1 = nullptr;
    f_value = false;
    _read();
}

void id3v2_4_t::u2be_synchsafe_t::_read() {
    m_byte0 = std::unique_ptr<u1be_synchsafe_t>(new u1be_synchsafe_t(m__io, this, m__root));
    m_byte1 = std::unique_ptr<u1be_synchsafe_t>(new u1be_synchsafe_t(m__io, this, m__root));
}

id3v2_4_t::u2be_synchsafe_t::~u2be_synchsafe_t() {
    _clean_up();
}

void id3v2_4_t::u2be_synchsafe_t::_clean_up() {
}

int32_t id3v2_4_t::u2be_synchsafe_t::value() {
    if (f_value)
        return m_value;
    m_value = ((byte0()->value() << 7) | byte1()->value());
    f_value = true;
    return m_value;
}

id3v2_4_t::tag_t::tag_t(kaitai::kstream* p__io, id3v2_4_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_header = nullptr;
    m_header_ex = nullptr;
    m_frames = nullptr;
    m_padding = nullptr;
    m_footer = nullptr;
    _read();
}

void id3v2_4_t::tag_t::_read() {
    m_header = std::unique_ptr<header_t>(new header_t(m__io, this, m__root));
    n_header_ex = true;
    if (header()->flags()->flag_headerex()) {
        n_header_ex = false;
        m_header_ex = std::unique_ptr<header_ex_t>(new header_ex_t(m__io, this, m__root));
    }
    m_frames = std::unique_ptr<std::vector<std::unique_ptr<frame_t>>>(new std::vector<std::unique_ptr<frame_t>>());
    {
        int i = 0;
        frame_t* _;
        do {
            _ = new frame_t(m__io, this, m__root);
            m_frames->push_back(std::move(std::unique_ptr<frame_t>(_)));
            i++;
        } while (!( (((_io()->pos() + _->size()->value()) > header()->size()->value()) || (_->is_invalid())) ));
    }
    n_padding = true;
    if (!(header()->flags()->flag_footer())) {
        n_padding = false;
        m_padding = std::unique_ptr<padding_t>(new padding_t(m__io, this, m__root));
    }
    n_footer = true;
    if (header()->flags()->flag_footer()) {
        n_footer = false;
        m_footer = std::unique_ptr<footer_t>(new footer_t(m__io, this, m__root));
    }
}

id3v2_4_t::tag_t::~tag_t() {
    _clean_up();
}

void id3v2_4_t::tag_t::_clean_up() {
    if (!n_header_ex) {
    }
    if (!n_padding) {
    }
    if (!n_footer) {
    }
}

id3v2_4_t::u4be_synchsafe_t::u4be_synchsafe_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_short0 = nullptr;
    m_short1 = nullptr;
    f_value = false;
    _read();
}

void id3v2_4_t::u4be_synchsafe_t::_read() {
    m_short0 = std::unique_ptr<u2be_synchsafe_t>(new u2be_synchsafe_t(m__io, this, m__root));
    m_short1 = std::unique_ptr<u2be_synchsafe_t>(new u2be_synchsafe_t(m__io, this, m__root));
}

id3v2_4_t::u4be_synchsafe_t::~u4be_synchsafe_t() {
    _clean_up();
}

void id3v2_4_t::u4be_synchsafe_t::_clean_up() {
}

int32_t id3v2_4_t::u4be_synchsafe_t::value() {
    if (f_value)
        return m_value;
    m_value = ((short0()->value() << 14) | short1()->value());
    f_value = true;
    return m_value;
}

id3v2_4_t::frame_t::frame_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_size = nullptr;
    m_flags_status = nullptr;
    m_flags_format = nullptr;
    f_is_invalid = false;
    _read();
}

void id3v2_4_t::frame_t::_read() {
    m_id = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), std::string("ASCII"));
    m_size = std::unique_ptr<u4be_synchsafe_t>(new u4be_synchsafe_t(m__io, this, m__root));
    m_flags_status = std::unique_ptr<flags_status_t>(new flags_status_t(m__io, this, m__root));
    m_flags_format = std::unique_ptr<flags_format_t>(new flags_format_t(m__io, this, m__root));
    m_data = m__io->read_bytes(size()->value());
}

id3v2_4_t::frame_t::~frame_t() {
    _clean_up();
}

void id3v2_4_t::frame_t::_clean_up() {
}

id3v2_4_t::frame_t::flags_status_t::flags_status_t(kaitai::kstream* p__io, id3v2_4_t::frame_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::frame_t::flags_status_t::_read() {
    m_reserved1 = m__io->read_bits_int_be(1);
    m_flag_discard_alter_tag = m__io->read_bits_int_be(1);
    m_flag_discard_alter_file = m__io->read_bits_int_be(1);
    m_flag_read_only = m__io->read_bits_int_be(1);
    m_reserved2 = m__io->read_bits_int_be(4);
}

id3v2_4_t::frame_t::flags_status_t::~flags_status_t() {
    _clean_up();
}

void id3v2_4_t::frame_t::flags_status_t::_clean_up() {
}

id3v2_4_t::frame_t::flags_format_t::flags_format_t(kaitai::kstream* p__io, id3v2_4_t::frame_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::frame_t::flags_format_t::_read() {
    m_reserved1 = m__io->read_bits_int_be(1);
    m_flag_grouping = m__io->read_bits_int_be(1);
    m_reserved2 = m__io->read_bits_int_be(2);
    m_flag_compressed = m__io->read_bits_int_be(1);
    m_flag_encrypted = m__io->read_bits_int_be(1);
    m_flag_unsynchronisated = m__io->read_bits_int_be(1);
    m_flag_indicator = m__io->read_bits_int_be(1);
}

id3v2_4_t::frame_t::flags_format_t::~flags_format_t() {
    _clean_up();
}

void id3v2_4_t::frame_t::flags_format_t::_clean_up() {
}

bool id3v2_4_t::frame_t::is_invalid() {
    if (f_is_invalid)
        return m_is_invalid;
    m_is_invalid = id() == (std::string("\000\000\000\000", 4));
    f_is_invalid = true;
    return m_is_invalid;
}

id3v2_4_t::header_ex_t::header_ex_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_size = nullptr;
    m_flags_ex = nullptr;
    _read();
}

void id3v2_4_t::header_ex_t::_read() {
    m_size = std::unique_ptr<u4be_synchsafe_t>(new u4be_synchsafe_t(m__io, this, m__root));
    m_flags_ex = std::unique_ptr<flags_ex_t>(new flags_ex_t(m__io, this, m__root));
    m_data = m__io->read_bytes((size()->value() - 5));
}

id3v2_4_t::header_ex_t::~header_ex_t() {
    _clean_up();
}

void id3v2_4_t::header_ex_t::_clean_up() {
}

id3v2_4_t::header_ex_t::flags_ex_t::flags_ex_t(kaitai::kstream* p__io, id3v2_4_t::header_ex_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::header_ex_t::flags_ex_t::_read() {
    m_reserved1 = m__io->read_bits_int_be(1);
    m_flag_update = m__io->read_bits_int_be(1);
    m_flag_crc = m__io->read_bits_int_be(1);
    m_flag_restrictions = m__io->read_bits_int_be(1);
    m_reserved2 = m__io->read_bits_int_be(4);
}

id3v2_4_t::header_ex_t::flags_ex_t::~flags_ex_t() {
    _clean_up();
}

void id3v2_4_t::header_ex_t::flags_ex_t::_clean_up() {
}

id3v2_4_t::header_t::header_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = nullptr;
    m_size = nullptr;
    _read();
}

void id3v2_4_t::header_t::_read() {
    m_magic = m__io->read_bytes(3);
    if (!(magic() == std::string("\x49\x44\x33", 3))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x49\x44\x33", 3), magic(), _io(), std::string("/types/header/seq/0"));
    }
    m_version_major = m__io->read_u1();
    m_version_revision = m__io->read_u1();
    m_flags = std::unique_ptr<flags_t>(new flags_t(m__io, this, m__root));
    m_size = std::unique_ptr<u4be_synchsafe_t>(new u4be_synchsafe_t(m__io, this, m__root));
}

id3v2_4_t::header_t::~header_t() {
    _clean_up();
}

void id3v2_4_t::header_t::_clean_up() {
}

id3v2_4_t::header_t::flags_t::flags_t(kaitai::kstream* p__io, id3v2_4_t::header_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::header_t::flags_t::_read() {
    m_flag_unsynchronization = m__io->read_bits_int_be(1);
    m_flag_headerex = m__io->read_bits_int_be(1);
    m_flag_experimental = m__io->read_bits_int_be(1);
    m_flag_footer = m__io->read_bits_int_be(1);
    m_reserved = m__io->read_bits_int_be(4);
}

id3v2_4_t::header_t::flags_t::~flags_t() {
    _clean_up();
}

void id3v2_4_t::header_t::flags_t::_clean_up() {
}

id3v2_4_t::padding_t::padding_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::padding_t::_read() {
    m_padding = m__io->read_bytes((_root()->tag()->header()->size()->value() - _io()->pos()));
}

id3v2_4_t::padding_t::~padding_t() {
    _clean_up();
}

void id3v2_4_t::padding_t::_clean_up() {
}

id3v2_4_t::footer_t::footer_t(kaitai::kstream* p__io, id3v2_4_t::tag_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = nullptr;
    m_size = nullptr;
    _read();
}

void id3v2_4_t::footer_t::_read() {
    m_magic = m__io->read_bytes(3);
    if (!(magic() == std::string("\x33\x44\x49", 3))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x33\x44\x49", 3), magic(), _io(), std::string("/types/footer/seq/0"));
    }
    m_version_major = m__io->read_u1();
    m_version_revision = m__io->read_u1();
    m_flags = std::unique_ptr<flags_t>(new flags_t(m__io, this, m__root));
    m_size = std::unique_ptr<u4be_synchsafe_t>(new u4be_synchsafe_t(m__io, this, m__root));
}

id3v2_4_t::footer_t::~footer_t() {
    _clean_up();
}

void id3v2_4_t::footer_t::_clean_up() {
}

id3v2_4_t::footer_t::flags_t::flags_t(kaitai::kstream* p__io, id3v2_4_t::footer_t* p__parent, id3v2_4_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void id3v2_4_t::footer_t::flags_t::_read() {
    m_flag_unsynchronization = m__io->read_bits_int_be(1);
    m_flag_headerex = m__io->read_bits_int_be(1);
    m_flag_experimental = m__io->read_bits_int_be(1);
    m_flag_footer = m__io->read_bits_int_be(1);
    m_reserved = m__io->read_bits_int_be(4);
}

id3v2_4_t::footer_t::flags_t::~flags_t() {
    _clean_up();
}

void id3v2_4_t::footer_t::flags_t::_clean_up() {
}