diff --git a/src/library/rekordbox/kaitaistructs/rekordbox_anlz.cpp b/src/library/rekordbox/kaitaistructs/rekordbox_anlz.cpp index 681d89e95e33..9311cfa8198a 100644 --- a/src/library/rekordbox/kaitaistructs/rekordbox_anlz.cpp +++ b/src/library/rekordbox/kaitaistructs/rekordbox_anlz.cpp @@ -2,45 +2,65 @@ #include "rekordbox_anlz.h" - +#include "kaitai/exceptions.h" rekordbox_anlz_t::rekordbox_anlz_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = this; + m_sections = nullptr; _read(); } void rekordbox_anlz_t::_read() { - m__unnamed0 = m__io->ensure_fixed_contents(std::string("\x50\x4D\x41\x49", 4)); + m_magic = m__io->read_bytes(4); + if (!(magic() == std::string("\x50\x4D\x41\x49", 4))) { + throw kaitai::validation_not_equal_error( + std::string("\x50\x4D\x41\x49", 4), + magic(), + _io(), + std::string("/seq/0")); + } m_len_header = m__io->read_u4be(); m_len_file = m__io->read_u4be(); m__unnamed3 = m__io->read_bytes((len_header() - _io()->pos())); - m_sections = new std::vector(); + m_sections = + std::unique_ptr>>( + new std::vector>()); { + int i = 0; while (!m__io->is_eof()) { - m_sections->push_back(new tagged_section_t(m__io, this, m__root)); + m_sections->push_back(std::move(std::unique_ptr( + new tagged_section_t(m__io, this, m__root)))); + i++; } } } rekordbox_anlz_t::~rekordbox_anlz_t() { - for (std::vector::iterator it = m_sections->begin(); it != m_sections->end(); ++it) { - delete *it; - } - delete m_sections; + _clean_up(); } -rekordbox_anlz_t::phrase_up_down_t::phrase_up_down_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { +void rekordbox_anlz_t::_clean_up() { +} + +rekordbox_anlz_t::phrase_mid_t::phrase_mid_t(kaitai::kstream* p__io, + rekordbox_anlz_t::song_structure_entry_t* p__parent, + rekordbox_anlz_t* p__root) + : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; _read(); } -void rekordbox_anlz_t::phrase_up_down_t::_read() { - m_id = static_cast(m__io->read_u2be()); +void rekordbox_anlz_t::phrase_mid_t::_read() { + m_id = static_cast(m__io->read_u2be()); +} + +rekordbox_anlz_t::phrase_mid_t::~phrase_mid_t() { + _clean_up(); } -rekordbox_anlz_t::phrase_up_down_t::~phrase_up_down_t() { +void rekordbox_anlz_t::phrase_mid_t::_clean_up() { } rekordbox_anlz_t::path_tag_t::path_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -59,6 +79,10 @@ void rekordbox_anlz_t::path_tag_t::_read() { } rekordbox_anlz_t::path_tag_t::~path_tag_t() { + _clean_up(); +} + +void rekordbox_anlz_t::path_tag_t::_clean_up() { if (!n_path) { } } @@ -70,16 +94,20 @@ rekordbox_anlz_t::wave_preview_tag_t::wave_preview_tag_t(kaitai::kstream* p__io, } void rekordbox_anlz_t::wave_preview_tag_t::_read() { - m_len_preview = m__io->read_u4be(); + m_len_data = m__io->read_u4be(); m__unnamed1 = m__io->read_u4be(); n_data = true; if (_parent()->len_tag() > _parent()->len_header()) { n_data = false; - m_data = m__io->read_bytes(len_preview()); + m_data = m__io->read_bytes(len_data()); } } rekordbox_anlz_t::wave_preview_tag_t::~wave_preview_tag_t() { + _clean_up(); +} + +void rekordbox_anlz_t::wave_preview_tag_t::_clean_up() { if (!n_data) { } } @@ -87,26 +115,63 @@ rekordbox_anlz_t::wave_preview_tag_t::~wave_preview_tag_t() { rekordbox_anlz_t::beat_grid_tag_t::beat_grid_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_beats = nullptr; _read(); } void rekordbox_anlz_t::beat_grid_tag_t::_read() { m__unnamed0 = m__io->read_u4be(); m__unnamed1 = m__io->read_u4be(); - m_len_beats = m__io->read_u4be(); - int l_beats = len_beats(); - m_beats = new std::vector(); - m_beats->reserve(l_beats); + m_num_beats = m__io->read_u4be(); + m_beats = std::unique_ptr>>( + new std::vector>()); + const int l_beats = num_beats(); for (int i = 0; i < l_beats; i++) { - m_beats->push_back(new beat_grid_beat_t(m__io, this, m__root)); + m_beats->push_back(std::move(std::unique_ptr( + new beat_grid_beat_t(m__io, this, m__root)))); } } rekordbox_anlz_t::beat_grid_tag_t::~beat_grid_tag_t() { - for (std::vector::iterator it = m_beats->begin(); it != m_beats->end(); ++it) { - delete *it; + _clean_up(); +} + +void rekordbox_anlz_t::beat_grid_tag_t::_clean_up() { +} + +rekordbox_anlz_t::song_structure_body_t::song_structure_body_t( + kaitai::kstream* p__io, + rekordbox_anlz_t::song_structure_tag_t* p__parent, + rekordbox_anlz_t* p__root) + : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_entries = nullptr; + _read(); +} + +void rekordbox_anlz_t::song_structure_body_t::_read() { + m_mood = static_cast(m__io->read_u2be()); + m__unnamed1 = m__io->read_bytes(6); + m_end_beat = m__io->read_u2be(); + m__unnamed3 = m__io->read_bytes(2); + m_bank = static_cast(m__io->read_u1()); + m__unnamed5 = m__io->read_bytes(1); + m_entries = std::unique_ptr< + std::vector>>( + new std::vector>()); + const int l_entries = _parent()->len_entries(); + for (int i = 0; i < l_entries; i++) { + m_entries->push_back(std::move(std::unique_ptr( + new song_structure_entry_t(m__io, this, m__root)))); } - delete m_beats; +} + +rekordbox_anlz_t::song_structure_body_t::~song_structure_body_t() { + _clean_up(); +} + +void rekordbox_anlz_t::song_structure_body_t::_clean_up() { } rekordbox_anlz_t::wave_color_preview_tag_t::wave_color_preview_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -123,63 +188,109 @@ void rekordbox_anlz_t::wave_color_preview_tag_t::_read() { } rekordbox_anlz_t::wave_color_preview_tag_t::~wave_color_preview_tag_t() { + _clean_up(); +} + +void rekordbox_anlz_t::wave_color_preview_tag_t::_clean_up() { } -rekordbox_anlz_t::wave_scroll_tag_t::wave_scroll_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { +rekordbox_anlz_t::phrase_high_t::phrase_high_t(kaitai::kstream* p__io, + rekordbox_anlz_t::song_structure_entry_t* p__parent, + rekordbox_anlz_t* p__root) + : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; _read(); } -void rekordbox_anlz_t::wave_scroll_tag_t::_read() { - m_len_entry_bytes = m__io->read_u4be(); - m_len_entries = m__io->read_u4be(); - m__unnamed2 = m__io->read_u4be(); - m_entries = m__io->read_bytes((len_entries() * len_entry_bytes())); +void rekordbox_anlz_t::phrase_high_t::_read() { + m_id = static_cast(m__io->read_u2be()); } -rekordbox_anlz_t::wave_scroll_tag_t::~wave_scroll_tag_t() { +rekordbox_anlz_t::phrase_high_t::~phrase_high_t() { + _clean_up(); +} + +void rekordbox_anlz_t::phrase_high_t::_clean_up() { } -rekordbox_anlz_t::phrase_verse_bridge_t::phrase_verse_bridge_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { +rekordbox_anlz_t::wave_scroll_tag_t::wave_scroll_tag_t(kaitai::kstream* p__io, + rekordbox_anlz_t::tagged_section_t* p__parent, + rekordbox_anlz_t* p__root) + : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; _read(); } -void rekordbox_anlz_t::phrase_verse_bridge_t::_read() { - m_id = static_cast(m__io->read_u2be()); +void rekordbox_anlz_t::wave_scroll_tag_t::_read() { + m_len_entry_bytes = m__io->read_u4be(); + m_len_entries = m__io->read_u4be(); + m__unnamed2 = m__io->read_u4be(); + m_entries = m__io->read_bytes((len_entries() * len_entry_bytes())); } -rekordbox_anlz_t::phrase_verse_bridge_t::~phrase_verse_bridge_t() { +rekordbox_anlz_t::wave_scroll_tag_t::~wave_scroll_tag_t() { + _clean_up(); +} + +void rekordbox_anlz_t::wave_scroll_tag_t::_clean_up() { } rekordbox_anlz_t::song_structure_tag_t::song_structure_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_body = nullptr; + m__io__raw_body = nullptr; + f_c = false; + f_raw_mood = false; + f_is_masked = false; _read(); } void rekordbox_anlz_t::song_structure_tag_t::_read() { m_len_entry_bytes = m__io->read_u4be(); m_len_entries = m__io->read_u2be(); - m_style = m__io->read_u2be(); - m__unnamed3 = m__io->read_bytes(6); - m_end_beat = m__io->read_u2be(); - m__unnamed5 = m__io->read_bytes(4); - int l_entries = len_entries(); - m_entries = new std::vector(); - m_entries->reserve(l_entries); - for (int i = 0; i < l_entries; i++) { - m_entries->push_back(new song_structure_entry_t(m__io, this, m__root)); - } + m__raw_body = m__io->read_bytes_full(); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new song_structure_body_t(m__io__raw_body.get(), this, m__root)); } rekordbox_anlz_t::song_structure_tag_t::~song_structure_tag_t() { - for (std::vector::iterator it = m_entries->begin(); it != m_entries->end(); ++it) { - delete *it; + _clean_up(); +} + +void rekordbox_anlz_t::song_structure_tag_t::_clean_up() { + if (f_raw_mood) { } - delete m_entries; +} + +uint16_t rekordbox_anlz_t::song_structure_tag_t::c() { + if (f_c) + return m_c; + m_c = len_entries(); + f_c = true; + return m_c; +} + +uint16_t rekordbox_anlz_t::song_structure_tag_t::raw_mood() { + if (f_raw_mood) + return m_raw_mood; + std::streampos _pos = m__io->pos(); + m__io->seek(6); + m_raw_mood = m__io->read_u2be(); + m__io->seek(_pos); + f_raw_mood = true; + return m_raw_mood; +} + +bool rekordbox_anlz_t::song_structure_tag_t::is_masked() { + if (f_is_masked) + return m_is_masked; + m_is_masked = raw_mood() > 20; + f_is_masked = true; + return m_is_masked; } rekordbox_anlz_t::cue_extended_entry_t::cue_extended_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::cue_extended_tag_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -189,7 +300,14 @@ rekordbox_anlz_t::cue_extended_entry_t::cue_extended_entry_t(kaitai::kstream* p_ } void rekordbox_anlz_t::cue_extended_entry_t::_read() { - m__unnamed0 = m__io->ensure_fixed_contents(std::string("\x50\x43\x50\x32", 4)); + m_magic = m__io->read_bytes(4); + if (!(magic() == std::string("\x50\x43\x50\x32", 4))) { + throw kaitai::validation_not_equal_error( + std::string("\x50\x43\x50\x32", 4), + magic(), + _io(), + std::string("/types/cue_extended_entry/seq/0")); + } m_len_header = m__io->read_u4be(); m_len_entry = m__io->read_u4be(); m_hot_cue = m__io->read_u4be(); @@ -198,7 +316,9 @@ void rekordbox_anlz_t::cue_extended_entry_t::_read() { m_time = m__io->read_u4be(); m_loop_time = m__io->read_u4be(); m_color_id = m__io->read_u1(); - m__unnamed9 = m__io->read_bytes(11); + m__unnamed9 = m__io->read_bytes(7); + m_loop_numerator = m__io->read_u2be(); + m_loop_denominator = m__io->read_u2be(); n_len_comment = true; if (len_entry() > 43) { n_len_comment = false; @@ -229,14 +349,18 @@ void rekordbox_anlz_t::cue_extended_entry_t::_read() { n_color_blue = false; m_color_blue = m__io->read_u1(); } - n__unnamed16 = true; + n__unnamed18 = true; if ((len_entry() - len_comment()) > 48) { - n__unnamed16 = false; - m__unnamed16 = m__io->read_bytes(((len_entry() - 48) - len_comment())); + n__unnamed18 = false; + m__unnamed18 = m__io->read_bytes(((len_entry() - 48) - len_comment())); } } rekordbox_anlz_t::cue_extended_entry_t::~cue_extended_entry_t() { + _clean_up(); +} + +void rekordbox_anlz_t::cue_extended_entry_t::_clean_up() { if (!n_len_comment) { } if (!n_comment) { @@ -249,60 +373,85 @@ rekordbox_anlz_t::cue_extended_entry_t::~cue_extended_entry_t() { } if (!n_color_blue) { } - if (!n__unnamed16) { + if (!n__unnamed18) { } } rekordbox_anlz_t::vbr_tag_t::vbr_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_index = nullptr; _read(); } void rekordbox_anlz_t::vbr_tag_t::_read() { m__unnamed0 = m__io->read_u4be(); - int l_index = 400; - m_index = new std::vector(); - m_index->reserve(l_index); + m_index = std::unique_ptr>(new std::vector()); + const int l_index = 400; for (int i = 0; i < l_index; i++) { - m_index->push_back(m__io->read_u4be()); + m_index->push_back(std::move(m__io->read_u4be())); } } rekordbox_anlz_t::vbr_tag_t::~vbr_tag_t() { - delete m_index; + _clean_up(); } -rekordbox_anlz_t::song_structure_entry_t::song_structure_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_tag_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { +void rekordbox_anlz_t::vbr_tag_t::_clean_up() { +} + +rekordbox_anlz_t::song_structure_entry_t::song_structure_entry_t( + kaitai::kstream* p__io, + rekordbox_anlz_t::song_structure_body_t* p__parent, + rekordbox_anlz_t* p__root) + : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; _read(); } void rekordbox_anlz_t::song_structure_entry_t::_read() { - m_phrase_number = m__io->read_u2be(); - m_beat_number = m__io->read_u2be(); - switch (_parent()->style()) { - case 1: { - m_phrase_id = new phrase_up_down_t(m__io, this, m__root); + m_index = m__io->read_u2be(); + m_beat = m__io->read_u2be(); + switch (_parent()->mood()) { + case rekordbox_anlz_t::TRACK_MOOD_HIGH: { + m_kind = std::unique_ptr(new phrase_high_t(m__io, this, m__root)); + break; + } + case rekordbox_anlz_t::TRACK_MOOD_MID: { + m_kind = std::unique_ptr(new phrase_mid_t(m__io, this, m__root)); break; } - case 2: { - m_phrase_id = new phrase_verse_bridge_t(m__io, this, m__root); + case rekordbox_anlz_t::TRACK_MOOD_LOW: { + m_kind = std::unique_ptr(new phrase_low_t(m__io, this, m__root)); break; } default: { - m_phrase_id = new phrase_verse_bridge_t(m__io, this, m__root); + m_kind = std::unique_ptr(new phrase_mid_t(m__io, this, m__root)); break; } } - m__unnamed3 = m__io->read_bytes((_parent()->len_entry_bytes() - 9)); - m_fill_in = m__io->read_u1(); - m_fill_in_beat_number = m__io->read_u2be(); + m__unnamed3 = m__io->read_bytes(1); + m_k1 = m__io->read_u1(); + m__unnamed5 = m__io->read_bytes(1); + m_k2 = m__io->read_u1(); + m__unnamed7 = m__io->read_bytes(1); + m_b = m__io->read_u1(); + m_beat2 = m__io->read_u2be(); + m_beat3 = m__io->read_u2be(); + m_beat4 = m__io->read_u2be(); + m__unnamed12 = m__io->read_bytes(1); + m_k3 = m__io->read_u1(); + m__unnamed14 = m__io->read_bytes(1); + m_fill = m__io->read_u1(); + m_beat_fill = m__io->read_u2be(); } rekordbox_anlz_t::song_structure_entry_t::~song_structure_entry_t() { - delete m_phrase_id; + _clean_up(); +} + +void rekordbox_anlz_t::song_structure_entry_t::_clean_up() { } rekordbox_anlz_t::cue_entry_t::cue_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::cue_tag_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -312,7 +461,14 @@ rekordbox_anlz_t::cue_entry_t::cue_entry_t(kaitai::kstream* p__io, rekordbox_anl } void rekordbox_anlz_t::cue_entry_t::_read() { - m__unnamed0 = m__io->ensure_fixed_contents(std::string("\x50\x43\x50\x54", 4)); + m_magic = m__io->read_bytes(4); + if (!(magic() == std::string("\x50\x43\x50\x54", 4))) { + throw kaitai::validation_not_equal_error( + std::string("\x50\x43\x50\x54", 4), + magic(), + _io(), + std::string("/types/cue_entry/seq/0")); + } m_len_header = m__io->read_u4be(); m_len_entry = m__io->read_u4be(); m_hot_cue = m__io->read_u4be(); @@ -328,6 +484,10 @@ void rekordbox_anlz_t::cue_entry_t::_read() { } rekordbox_anlz_t::cue_entry_t::~cue_entry_t() { + _clean_up(); +} + +void rekordbox_anlz_t::cue_entry_t::_clean_up() { } rekordbox_anlz_t::beat_grid_beat_t::beat_grid_beat_t(kaitai::kstream* p__io, rekordbox_anlz_t::beat_grid_tag_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -343,31 +503,58 @@ void rekordbox_anlz_t::beat_grid_beat_t::_read() { } rekordbox_anlz_t::beat_grid_beat_t::~beat_grid_beat_t() { + _clean_up(); +} + +void rekordbox_anlz_t::beat_grid_beat_t::_clean_up() { } rekordbox_anlz_t::cue_extended_tag_t::cue_extended_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_cues = nullptr; _read(); } void rekordbox_anlz_t::cue_extended_tag_t::_read() { m_type = static_cast(m__io->read_u4be()); - m_len_cues = m__io->read_u2be(); + m_num_cues = m__io->read_u2be(); m__unnamed2 = m__io->read_bytes(2); - int l_cues = len_cues(); - m_cues = new std::vector(); - m_cues->reserve(l_cues); + m_cues = + std::unique_ptr>>( + new std::vector>()); + const int l_cues = num_cues(); for (int i = 0; i < l_cues; i++) { - m_cues->push_back(new cue_extended_entry_t(m__io, this, m__root)); + m_cues->push_back(std::move(std::unique_ptr( + new cue_extended_entry_t(m__io, this, m__root)))); } } rekordbox_anlz_t::cue_extended_tag_t::~cue_extended_tag_t() { - for (std::vector::iterator it = m_cues->begin(); it != m_cues->end(); ++it) { - delete *it; - } - delete m_cues; + _clean_up(); +} + +void rekordbox_anlz_t::cue_extended_tag_t::_clean_up() { +} + +rekordbox_anlz_t::phrase_low_t::phrase_low_t(kaitai::kstream* p__io, + rekordbox_anlz_t::song_structure_entry_t* p__parent, + rekordbox_anlz_t* p__root) + : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void rekordbox_anlz_t::phrase_low_t::_read() { + m_id = static_cast(m__io->read_u2be()); +} + +rekordbox_anlz_t::phrase_low_t::~phrase_low_t() { + _clean_up(); +} + +void rekordbox_anlz_t::phrase_low_t::_clean_up() { } rekordbox_anlz_t::unknown_tag_t::unknown_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -380,97 +567,115 @@ void rekordbox_anlz_t::unknown_tag_t::_read() { } rekordbox_anlz_t::unknown_tag_t::~unknown_tag_t() { + _clean_up(); +} + +void rekordbox_anlz_t::unknown_tag_t::_clean_up() { } rekordbox_anlz_t::tagged_section_t::tagged_section_t(kaitai::kstream* p__io, rekordbox_anlz_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m__io__raw_body = nullptr; _read(); } void rekordbox_anlz_t::tagged_section_t::_read() { - m_fourcc = m__io->read_s4be(); + m_fourcc = static_cast(m__io->read_s4be()); m_len_header = m__io->read_u4be(); m_len_tag = m__io->read_u4be(); switch (fourcc()) { - case 1346588482: { + case rekordbox_anlz_t::SECTION_TAGS_WAVE_COLOR_SCROLL: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new cue_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new wave_color_scroll_tag_t( + m__io__raw_body.get(), this, m__root)); break; } - case 1347900978: { + case rekordbox_anlz_t::SECTION_TAGS_WAVE_SCROLL: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new wave_preview_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new wave_scroll_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347900980: { + case rekordbox_anlz_t::SECTION_TAGS_VBR: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new wave_color_preview_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr(new vbr_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347895638: { + case rekordbox_anlz_t::SECTION_TAGS_CUES_2: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new wave_preview_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new cue_extended_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347900979: { + case rekordbox_anlz_t::SECTION_TAGS_CUES: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new wave_scroll_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr(new cue_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347638089: { + case rekordbox_anlz_t::SECTION_TAGS_SONG_STRUCTURE: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new song_structure_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new song_structure_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347507290: { + case rekordbox_anlz_t::SECTION_TAGS_BEAT_GRID: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new beat_grid_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new beat_grid_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347830354: { + case rekordbox_anlz_t::SECTION_TAGS_WAVE_PREVIEW: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new vbr_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new wave_preview_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347900981: { + case rekordbox_anlz_t::SECTION_TAGS_WAVE_COLOR_PREVIEW: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new wave_color_scroll_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new wave_color_preview_tag_t( + m__io__raw_body.get(), this, m__root)); break; } - case 1346588466: { + case rekordbox_anlz_t::SECTION_TAGS_PATH: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new cue_extended_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr(new path_tag_t(m__io__raw_body.get(), this, m__root)); break; } - case 1347441736: { + case rekordbox_anlz_t::SECTION_TAGS_WAVE_TINY: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new path_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new wave_preview_tag_t(m__io__raw_body.get(), this, m__root)); break; } default: { m__raw_body = m__io->read_bytes((len_tag() - 12)); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new unknown_tag_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr( + new unknown_tag_t(m__io__raw_body.get(), this, m__root)); break; } } } rekordbox_anlz_t::tagged_section_t::~tagged_section_t() { - delete m__io__raw_body; - delete m_body; + _clean_up(); +} + +void rekordbox_anlz_t::tagged_section_t::_clean_up() { } rekordbox_anlz_t::wave_color_scroll_tag_t::wave_color_scroll_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { @@ -487,30 +692,36 @@ void rekordbox_anlz_t::wave_color_scroll_tag_t::_read() { } rekordbox_anlz_t::wave_color_scroll_tag_t::~wave_color_scroll_tag_t() { + _clean_up(); +} + +void rekordbox_anlz_t::wave_color_scroll_tag_t::_clean_up() { } rekordbox_anlz_t::cue_tag_t::cue_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent, rekordbox_anlz_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_cues = nullptr; _read(); } void rekordbox_anlz_t::cue_tag_t::_read() { m_type = static_cast(m__io->read_u4be()); m__unnamed1 = m__io->read_bytes(2); - m_len_cues = m__io->read_u2be(); + m_num_cues = m__io->read_u2be(); m_memory_count = m__io->read_u4be(); - int l_cues = len_cues(); - m_cues = new std::vector(); - m_cues->reserve(l_cues); + m_cues = std::unique_ptr>>( + new std::vector>()); + const int l_cues = num_cues(); for (int i = 0; i < l_cues; i++) { - m_cues->push_back(new cue_entry_t(m__io, this, m__root)); + m_cues->push_back(std::move(std::unique_ptr( + new cue_entry_t(m__io, this, m__root)))); } } rekordbox_anlz_t::cue_tag_t::~cue_tag_t() { - for (std::vector::iterator it = m_cues->begin(); it != m_cues->end(); ++it) { - delete *it; - } - delete m_cues; + _clean_up(); +} + +void rekordbox_anlz_t::cue_tag_t::_clean_up() { } diff --git a/src/library/rekordbox/kaitaistructs/rekordbox_anlz.h b/src/library/rekordbox/kaitaistructs/rekordbox_anlz.h index 43ae586894df..44d378c450cc 100644 --- a/src/library/rekordbox/kaitaistructs/rekordbox_anlz.h +++ b/src/library/rekordbox/kaitaistructs/rekordbox_anlz.h @@ -5,10 +5,11 @@ #include "kaitai/kaitaistruct.h" #include +#include #include -#if KAITAI_STRUCT_VERSION < 7000L -#error "Incompatible Kaitai Struct C++/STL API: version 0.7 or later is required" +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" #endif /** @@ -19,25 +20,26 @@ * inside variable bit-rate audio streams, and lists of memory cues * and loop points. They are used by Pioneer professional DJ * equipment. - * + * * The format has been reverse-engineered to facilitate sophisticated * integrations with light and laser shows, videos, and other musical * instruments, by supporting deep knowledge of what is playing and * what is coming next through monitoring the network communications * of the players. - * \sa Source + * \sa https://reverseengineering.stackexchange.com/questions/4311/help-reversing-a-edb-database-file-for-pioneers-rekordbox-software Source */ class rekordbox_anlz_t : public kaitai::kstruct { public: - class phrase_up_down_t; + class phrase_mid_t; class path_tag_t; class wave_preview_tag_t; class beat_grid_tag_t; + class song_structure_body_t; class wave_color_preview_tag_t; + class phrase_high_t; class wave_scroll_tag_t; - class phrase_verse_bridge_t; class song_structure_tag_t; class cue_extended_entry_t; class vbr_tag_t; @@ -45,6 +47,7 @@ class rekordbox_anlz_t : public kaitai::kstruct { class cue_entry_t; class beat_grid_beat_t; class cue_extended_tag_t; + class phrase_low_t; class unknown_tag_t; class tagged_section_t; class wave_color_scroll_tag_t; @@ -52,7 +55,8 @@ class rekordbox_anlz_t : public kaitai::kstruct { enum cue_entry_status_t { CUE_ENTRY_STATUS_DISABLED = 0, - CUE_ENTRY_STATUS_ENABLED = 1 + CUE_ENTRY_STATUS_ENABLED = 1, + CUE_ENTRY_STATUS_ACTIVE_LOOP = 4 }; enum cue_list_type_t { @@ -60,10 +64,24 @@ class rekordbox_anlz_t : public kaitai::kstruct { CUE_LIST_TYPE_HOT_CUES = 1 }; - enum phrase_style_t { - PHRASE_STYLE_UP_DOWN = 1, - PHRASE_STYLE_VERSE_BRIDGE = 2, - PHRASE_STYLE_VERSE_BRIDGE_2 = 3 + enum mood_high_phrase_t { + MOOD_HIGH_PHRASE_INTRO = 1, + MOOD_HIGH_PHRASE_UP = 2, + MOOD_HIGH_PHRASE_DOWN = 3, + MOOD_HIGH_PHRASE_CHORUS = 5, + MOOD_HIGH_PHRASE_OUTRO = 6 + }; + + enum track_bank_t { + TRACK_BANK_DEFAULT = 0, + TRACK_BANK_COOL = 1, + TRACK_BANK_NATURAL = 2, + TRACK_BANK_HOT = 3, + TRACK_BANK_SUBTLE = 4, + TRACK_BANK_WARM = 5, + TRACK_BANK_VIVID = 6, + TRACK_BANK_CLUB_1 = 7, + TRACK_BANK_CLUB_2 = 8 }; enum cue_entry_type_t { @@ -85,54 +103,67 @@ class rekordbox_anlz_t : public kaitai::kstruct { SECTION_TAGS_WAVE_COLOR_SCROLL = 1347900981 }; - enum phrase_verse_bridge_id_t { - PHRASE_VERSE_BRIDGE_ID_INTRO = 1, - PHRASE_VERSE_BRIDGE_ID_VERSE1 = 2, - PHRASE_VERSE_BRIDGE_ID_VERSE2 = 3, - PHRASE_VERSE_BRIDGE_ID_VERSE3 = 4, - PHRASE_VERSE_BRIDGE_ID_VERSE4 = 5, - PHRASE_VERSE_BRIDGE_ID_VERSE5 = 6, - PHRASE_VERSE_BRIDGE_ID_VERSE6 = 7, - PHRASE_VERSE_BRIDGE_ID_BRIDGE = 8, - PHRASE_VERSE_BRIDGE_ID_CHORUS = 9, - PHRASE_VERSE_BRIDGE_ID_OUTRO = 10 + enum track_mood_t { + TRACK_MOOD_HIGH = 1, + TRACK_MOOD_MID = 2, + TRACK_MOOD_LOW = 3 + }; + + enum mood_mid_phrase_t { + MOOD_MID_PHRASE_INTRO = 1, + MOOD_MID_PHRASE_VERSE_1 = 2, + MOOD_MID_PHRASE_VERSE_2 = 3, + MOOD_MID_PHRASE_VERSE_3 = 4, + MOOD_MID_PHRASE_VERSE_4 = 5, + MOOD_MID_PHRASE_VERSE_5 = 6, + MOOD_MID_PHRASE_VERSE_6 = 7, + MOOD_MID_PHRASE_BRIDGE = 8, + MOOD_MID_PHRASE_CHORUS = 9, + MOOD_MID_PHRASE_OUTRO = 10 }; - enum phrase_up_down_id_t { - PHRASE_UP_DOWN_ID_INTRO = 1, - PHRASE_UP_DOWN_ID_UP = 2, - PHRASE_UP_DOWN_ID_DOWN = 3, - PHRASE_UP_DOWN_ID_CHORUS = 5, - PHRASE_UP_DOWN_ID_OUTRO = 6 + enum mood_low_phrase_t { + MOOD_LOW_PHRASE_INTRO = 1, + MOOD_LOW_PHRASE_VERSE_1 = 2, + MOOD_LOW_PHRASE_VERSE_1B = 3, + MOOD_LOW_PHRASE_VERSE_1C = 4, + MOOD_LOW_PHRASE_VERSE_2 = 5, + MOOD_LOW_PHRASE_VERSE_2B = 6, + MOOD_LOW_PHRASE_VERSE_2C = 7, + MOOD_LOW_PHRASE_BRIDGE = 8, + MOOD_LOW_PHRASE_CHORUS = 9, + MOOD_LOW_PHRASE_OUTRO = 10 }; - rekordbox_anlz_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, rekordbox_anlz_t* p__root = 0); + rekordbox_anlz_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~rekordbox_anlz_t(); - class phrase_up_down_t : public kaitai::kstruct { + class phrase_mid_t : public kaitai::kstruct { public: - phrase_up_down_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + phrase_mid_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: - ~phrase_up_down_t(); + ~phrase_mid_t(); private: - phrase_up_down_id_t m_id; + mood_mid_phrase_t m_id; rekordbox_anlz_t* m__root; rekordbox_anlz_t::song_structure_entry_t* m__parent; public: - phrase_up_down_id_t id() const { return m_id; } + mood_mid_phrase_t id() const { return m_id; } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::song_structure_entry_t* _parent() const { return m__parent; } }; @@ -146,10 +177,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - path_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + path_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~path_tag_t(); @@ -182,16 +214,17 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - wave_preview_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + wave_preview_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~wave_preview_tag_t(); private: - uint32_t m_len_preview; + uint32_t m_len_data; uint32_t m__unnamed1; std::string m_data; bool n_data; @@ -210,7 +243,7 @@ class rekordbox_anlz_t : public kaitai::kstruct { * slightly redundant because it can be computed from the * length of the tag. */ - uint32_t len_preview() const { return m_len_preview; } + uint32_t len_data() const { return m_len_data; } uint32_t _unnamed1() const { return m__unnamed1; } /** @@ -231,10 +264,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - beat_grid_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + beat_grid_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~beat_grid_tag_t(); @@ -242,8 +276,8 @@ class rekordbox_anlz_t : public kaitai::kstruct { private: uint32_t m__unnamed0; uint32_t m__unnamed1; - uint32_t m_len_beats; - std::vector* m_beats; + uint32_t m_num_beats; + std::unique_ptr>> m_beats; rekordbox_anlz_t* m__root; rekordbox_anlz_t::tagged_section_t* m__parent; @@ -254,16 +288,71 @@ class rekordbox_anlz_t : public kaitai::kstruct { /** * The number of beat entries which follow. */ - uint32_t len_beats() const { return m_len_beats; } + uint32_t num_beats() const { return m_num_beats; } /** * The entries of the beat grid. */ - std::vector* beats() const { return m_beats; } + std::vector>* beats() const { return m_beats.get(); } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } }; + /** + * Stores the rest of the song structure tag, which can only be + * parsed after unmasking. + */ + + class song_structure_body_t : public kaitai::kstruct { + + public: + + song_structure_body_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_tag_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~song_structure_body_t(); + + private: + track_mood_t m_mood; + std::string m__unnamed1; + uint16_t m_end_beat; + std::string m__unnamed3; + track_bank_t m_bank; + std::string m__unnamed5; + std::unique_ptr>> m_entries; + rekordbox_anlz_t* m__root; + rekordbox_anlz_t::song_structure_tag_t* m__parent; + + public: + + /** + * The mood which rekordbox assigns the track as a whole during phrase analysis. + */ + track_mood_t mood() const { return m_mood; } + std::string _unnamed1() const { return m__unnamed1; } + + /** + * The beat number at which the last phrase ends. The track may + * continue after the last phrase ends. If this is the case, it will + * mostly be silence. + */ + uint16_t end_beat() const { return m_end_beat; } + std::string _unnamed3() const { return m__unnamed3; } + + /** + * The stylistic bank which can be assigned to the track in rekordbox Lighting mode. + */ + track_bank_t bank() const { return m_bank; } + std::string _unnamed5() const { return m__unnamed5; } + std::vector>* entries() const { return m_entries.get(); } + rekordbox_anlz_t* _root() const { return m__root; } + rekordbox_anlz_t::song_structure_tag_t* _parent() const { return m__parent; } + }; + /** * A larger, colorful waveform preview image suitable for display * above the touch strip for jumping to a track position on newer @@ -274,10 +363,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - wave_color_preview_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + wave_color_preview_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~wave_color_preview_tag_t(); @@ -308,6 +398,30 @@ class rekordbox_anlz_t : public kaitai::kstruct { rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } }; + class phrase_high_t : public kaitai::kstruct { + + public: + + phrase_high_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~phrase_high_t(); + + private: + mood_high_phrase_t m_id; + rekordbox_anlz_t* m__root; + rekordbox_anlz_t::song_structure_entry_t* m__parent; + + public: + mood_high_phrase_t id() const { return m_id; } + rekordbox_anlz_t* _root() const { return m__root; } + rekordbox_anlz_t::song_structure_entry_t* _parent() const { return m__parent; } + }; + /** * A larger waveform image suitable for scrolling along as a track * plays. @@ -317,10 +431,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - wave_scroll_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + wave_scroll_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~wave_scroll_tag_t(); @@ -351,56 +466,58 @@ class rekordbox_anlz_t : public kaitai::kstruct { rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } }; - class phrase_verse_bridge_t : public kaitai::kstruct { + /** + * Stores the song structure, also known as phrases (intro, verse, + * bridge, chorus, up, down, outro). + */ + + class song_structure_tag_t : public kaitai::kstruct { public: - phrase_verse_bridge_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + song_structure_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: - ~phrase_verse_bridge_t(); + ~song_structure_tag_t(); private: - phrase_verse_bridge_id_t m_id; - rekordbox_anlz_t* m__root; - rekordbox_anlz_t::song_structure_entry_t* m__parent; + bool f_c; + uint16_t m_c; public: - phrase_verse_bridge_id_t id() const { return m_id; } - rekordbox_anlz_t* _root() const { return m__root; } - rekordbox_anlz_t::song_structure_entry_t* _parent() const { return m__parent; } - }; - - /** - * Stores the song structure, also known as phrases (intro, verse, - * bridge, chorus, up, down, outro). - */ + uint16_t c(); - class song_structure_tag_t : public kaitai::kstruct { + private: + bool f_raw_mood; + uint16_t m_raw_mood; public: - song_structure_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + /** + * This is a way to tell whether the rest of the tag has been masked. The value is supposed + * to range from 1 to 3, but in masked files it will be much larger. + */ + uint16_t raw_mood(); private: - void _read(); + bool f_is_masked; + bool m_is_masked; public: - ~song_structure_tag_t(); + bool is_masked(); private: uint32_t m_len_entry_bytes; uint16_t m_len_entries; - uint16_t m_style; - std::string m__unnamed3; - uint16_t m_end_beat; - std::string m__unnamed5; - std::vector* m_entries; + std::unique_ptr m_body; rekordbox_anlz_t* m__root; rekordbox_anlz_t::tagged_section_t* m__parent; + std::string m__raw_body; + std::unique_ptr m__io__raw_body; public: @@ -415,27 +532,14 @@ class rekordbox_anlz_t : public kaitai::kstruct { uint16_t len_entries() const { return m_len_entries; } /** - * The phrase style. 1 is the up-down style - * (white label text in rekordbox) where the main phrases consist - * of up, down, and chorus. 2 is the bridge-verse style - * (black label text in rekordbox) where the main phrases consist - * of verse, chorus, and bridge. Style 3 is mostly identical to - * bridge-verse style except verses 1-3 are labeled VERSE1 and verses - * 4-6 are labeled VERSE2 in rekordbox. + * The rest of the tag, which needs to be unmasked before it + * can be parsed. */ - uint16_t style() const { return m_style; } - std::string _unnamed3() const { return m__unnamed3; } - - /** - * The beat number at which the last phrase ends. The track may - * continue after the last phrase ends. If this is the case, it will - * mostly be silence. - */ - uint16_t end_beat() const { return m_end_beat; } - std::string _unnamed5() const { return m__unnamed5; } - std::vector* entries() const { return m_entries; } + song_structure_body_t* body() const { return m_body.get(); } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } + std::string _raw_body() const { return m__raw_body; } + kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); } }; /** @@ -447,16 +551,17 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - cue_extended_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::cue_extended_tag_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + cue_extended_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::cue_extended_tag_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~cue_extended_entry_t(); private: - std::string m__unnamed0; + std::string m_magic; uint32_t m_len_header; uint32_t m_len_entry; uint32_t m_hot_cue; @@ -466,6 +571,8 @@ class rekordbox_anlz_t : public kaitai::kstruct { uint32_t m_loop_time; uint8_t m_color_id; std::string m__unnamed9; + uint16_t m_loop_numerator; + uint16_t m_loop_denominator; uint32_t m_len_comment; bool n_len_comment; @@ -508,18 +615,22 @@ class rekordbox_anlz_t : public kaitai::kstruct { bool _is_null_color_blue() { color_blue(); return n_color_blue; }; private: - std::string m__unnamed16; - bool n__unnamed16; + std::string m__unnamed18; + bool n__unnamed18; public: - bool _is_null__unnamed16() { _unnamed16(); return n__unnamed16; }; + bool _is_null__unnamed18() { _unnamed18(); return n__unnamed18; }; private: rekordbox_anlz_t* m__root; rekordbox_anlz_t::cue_extended_tag_t* m__parent; public: - std::string _unnamed0() const { return m__unnamed0; } + + /** + * Identifies this as an extended cue list entry (cue point). + */ + std::string magic() const { return m_magic; } uint32_t len_header() const { return m_len_header; } uint32_t len_entry() const { return m_len_entry; } @@ -530,7 +641,7 @@ class rekordbox_anlz_t : public kaitai::kstruct { uint32_t hot_cue() const { return m_hot_cue; } /** - * Indicates whether this is a memory cue or a loop. + * Indicates whether this is a regular cue point or a loop. */ cue_entry_type_t type() const { return m_type; } std::string _unnamed5() const { return m__unnamed5; } @@ -548,11 +659,23 @@ class rekordbox_anlz_t : public kaitai::kstruct { uint32_t loop_time() const { return m_loop_time; } /** - * References a row in the colors table if the memory cue or loop - * has been assigned a color + * References a row in the colors table if this is a memory cue or loop + * and has been assigned a color. */ uint8_t color_id() const { return m_color_id; } std::string _unnamed9() const { return m__unnamed9; } + + /** + * The numerator of the loop length in beats. + * Zero if the loop is not quantized. + */ + uint16_t loop_numerator() const { return m_loop_numerator; } + + /** + * The denominator of the loop length in beats. + * Zero if the loop is not quantized. + */ + uint16_t loop_denominator() const { return m_loop_denominator; } uint32_t len_comment() const { return m_len_comment; } /** @@ -561,25 +684,25 @@ class rekordbox_anlz_t : public kaitai::kstruct { std::string comment() const { return m_comment; } /** - * A lookup value for a color table? We use this to index to the colors shown in rekordbox. + * A lookup value for a color table? We use this to index to the hot cue colors shown in rekordbox. */ uint8_t color_code() const { return m_color_code; } /** - * The red component of the color to be displayed. + * The red component of the hot cue color to be displayed. */ uint8_t color_red() const { return m_color_red; } /** - * The green component of the color to be displayed. + * The green component of the hot cue color to be displayed. */ uint8_t color_green() const { return m_color_green; } /** - * The blue component of the color to be displayed. + * The blue component of the hot cue color to be displayed. */ uint8_t color_blue() const { return m_color_blue; } - std::string _unnamed16() const { return m__unnamed16; } + std::string _unnamed18() const { return m__unnamed18; } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::cue_extended_tag_t* _parent() const { return m__parent; } }; @@ -593,23 +716,24 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - vbr_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + vbr_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~vbr_tag_t(); private: uint32_t m__unnamed0; - std::vector* m_index; + std::unique_ptr> m_index; rekordbox_anlz_t* m__root; rekordbox_anlz_t::tagged_section_t* m__parent; public: uint32_t _unnamed0() const { return m__unnamed0; } - std::vector* index() const { return m_index; } + std::vector* index() const { return m_index.get(); } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } }; @@ -622,53 +746,106 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - song_structure_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_tag_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + song_structure_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_body_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~song_structure_entry_t(); private: - uint16_t m_phrase_number; - uint16_t m_beat_number; - kaitai::kstruct* m_phrase_id; + uint16_t m_index; + uint16_t m_beat; + std::unique_ptr m_kind; std::string m__unnamed3; - uint8_t m_fill_in; - uint16_t m_fill_in_beat_number; + uint8_t m_k1; + std::string m__unnamed5; + uint8_t m_k2; + std::string m__unnamed7; + uint8_t m_b; + uint16_t m_beat2; + uint16_t m_beat3; + uint16_t m_beat4; + std::string m__unnamed12; + uint8_t m_k3; + std::string m__unnamed14; + uint8_t m_fill; + uint16_t m_beat_fill; rekordbox_anlz_t* m__root; - rekordbox_anlz_t::song_structure_tag_t* m__parent; + rekordbox_anlz_t::song_structure_body_t* m__parent; public: /** * The absolute number of the phrase, starting at one. */ - uint16_t phrase_number() const { return m_phrase_number; } + uint16_t index() const { return m_index; } /** * The beat number at which the phrase starts. */ - uint16_t beat_number() const { return m_beat_number; } + uint16_t beat() const { return m_beat; } /** - * Identifier of the phrase label. + * The kind of phrase as displayed in rekordbox. */ - kaitai::kstruct* phrase_id() const { return m_phrase_id; } + kaitai::kstruct* kind() const { return m_kind.get(); } std::string _unnamed3() const { return m__unnamed3; } /** - * If nonzero, fill-in is present. + * One of three flags that identify phrase kind variants in high-mood tracks. + */ + uint8_t k1() const { return m_k1; } + std::string _unnamed5() const { return m__unnamed5; } + + /** + * One of three flags that identify phrase kind variants in high-mood tracks. */ - uint8_t fill_in() const { return m_fill_in; } + uint8_t k2() const { return m_k2; } + std::string _unnamed7() const { return m__unnamed7; } + + /** + * Flags how many more beat numbers are in a high-mood "Up 3" phrase. + */ + uint8_t b() const { return m_b; } + + /** + * Extra beat number (falling within phrase) always present in high-mood "Up 3" phrases. + */ + uint16_t beat2() const { return m_beat2; } + + /** + * Extra beat number (falling within phrase, larger than beat2) + * present in high-mood "Up 3" phrases when b has value 1. + */ + uint16_t beat3() const { return m_beat3; } + + /** + * Extra beat number (falling within phrase, larger than beat3) + * present in high-mood "Up 3" phrases when b has value 1. + */ + uint16_t beat4() const { return m_beat4; } + std::string _unnamed12() const { return m__unnamed12; } + + /** + * One of three flags that identify phrase kind variants in high-mood tracks. + */ + uint8_t k3() const { return m_k3; } + std::string _unnamed14() const { return m__unnamed14; } + + /** + * If nonzero, fill-in is present at end of phrase. + */ + uint8_t fill() const { return m_fill; } /** * The beat number at which fill-in starts. */ - uint16_t fill_in_beat_number() const { return m_fill_in_beat_number; } + uint16_t beat_fill() const { return m_beat_fill; } rekordbox_anlz_t* _root() const { return m__root; } - rekordbox_anlz_t::song_structure_tag_t* _parent() const { return m__parent; } + rekordbox_anlz_t::song_structure_body_t* _parent() const { return m__parent; } }; /** @@ -679,16 +856,17 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - cue_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::cue_tag_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + cue_entry_t(kaitai::kstream* p__io, rekordbox_anlz_t::cue_tag_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~cue_entry_t(); private: - std::string m__unnamed0; + std::string m_magic; uint32_t m_len_header; uint32_t m_len_entry; uint32_t m_hot_cue; @@ -705,7 +883,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { rekordbox_anlz_t::cue_tag_t* m__parent; public: - std::string _unnamed0() const { return m__unnamed0; } + + /** + * Identifies this as a cue list entry (cue point). + */ + std::string magic() const { return m_magic; } uint32_t len_header() const { return m_len_header; } uint32_t len_entry() const { return m_len_entry; } @@ -716,7 +898,7 @@ class rekordbox_anlz_t : public kaitai::kstruct { uint32_t hot_cue() const { return m_hot_cue; } /** - * If zero, this entry should be ignored. + * Indicates if this is an active loop. */ cue_entry_status_t status() const { return m_status; } uint32_t _unnamed5() const { return m__unnamed5; } @@ -761,10 +943,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - beat_grid_beat_t(kaitai::kstream* p__io, rekordbox_anlz_t::beat_grid_tag_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + beat_grid_beat_t(kaitai::kstream* p__io, rekordbox_anlz_t::beat_grid_tag_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~beat_grid_beat_t(); @@ -810,19 +993,20 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - cue_extended_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + cue_extended_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~cue_extended_tag_t(); private: cue_list_type_t m_type; - uint16_t m_len_cues; + uint16_t m_num_cues; std::string m__unnamed2; - std::vector* m_cues; + std::unique_ptr>> m_cues; rekordbox_anlz_t* m__root; rekordbox_anlz_t::tagged_section_t* m__parent; @@ -836,21 +1020,46 @@ class rekordbox_anlz_t : public kaitai::kstruct { /** * The length of the cue comment list. */ - uint16_t len_cues() const { return m_len_cues; } + uint16_t num_cues() const { return m_num_cues; } std::string _unnamed2() const { return m__unnamed2; } - std::vector* cues() const { return m_cues; } + std::vector>* cues() const { return m_cues.get(); } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } }; + class phrase_low_t : public kaitai::kstruct { + + public: + + phrase_low_t(kaitai::kstream* p__io, rekordbox_anlz_t::song_structure_entry_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~phrase_low_t(); + + private: + mood_low_phrase_t m_id; + rekordbox_anlz_t* m__root; + rekordbox_anlz_t::song_structure_entry_t* m__parent; + + public: + mood_low_phrase_t id() const { return m_id; } + rekordbox_anlz_t* _root() const { return m__root; } + rekordbox_anlz_t::song_structure_entry_t* _parent() const { return m__parent; } + }; + class unknown_tag_t : public kaitai::kstruct { public: - unknown_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + unknown_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~unknown_tag_t(); @@ -874,30 +1083,31 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - tagged_section_t(kaitai::kstream* p__io, rekordbox_anlz_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + tagged_section_t(kaitai::kstream* p__io, rekordbox_anlz_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~tagged_section_t(); private: - int32_t m_fourcc; + section_tags_t m_fourcc; uint32_t m_len_header; uint32_t m_len_tag; - kaitai::kstruct* m_body; + std::unique_ptr m_body; rekordbox_anlz_t* m__root; rekordbox_anlz_t* m__parent; std::string m__raw_body; - kaitai::kstream* m__io__raw_body; + std::unique_ptr m__io__raw_body; public: /** * A tag value indicating what kind of section this is. */ - int32_t fourcc() const { return m_fourcc; } + section_tags_t fourcc() const { return m_fourcc; } /** * The size, in bytes, of the header portion of the tag. @@ -908,11 +1118,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { * The size, in bytes, of this entire tag, counting the header. */ uint32_t len_tag() const { return m_len_tag; } - kaitai::kstruct* body() const { return m_body; } + kaitai::kstruct* body() const { return m_body.get(); } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t* _parent() const { return m__parent; } std::string _raw_body() const { return m__raw_body; } - kaitai::kstream* _io__raw_body() const { return m__io__raw_body; } + kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); } }; /** @@ -925,10 +1135,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - wave_color_scroll_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + wave_color_scroll_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~wave_color_scroll_tag_t(); @@ -968,10 +1179,11 @@ class rekordbox_anlz_t : public kaitai::kstruct { public: - cue_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = 0, rekordbox_anlz_t* p__root = 0); + cue_tag_t(kaitai::kstream* p__io, rekordbox_anlz_t::tagged_section_t* p__parent = nullptr, rekordbox_anlz_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~cue_tag_t(); @@ -979,9 +1191,9 @@ class rekordbox_anlz_t : public kaitai::kstruct { private: cue_list_type_t m_type; std::string m__unnamed1; - uint16_t m_len_cues; + uint16_t m_num_cues; uint32_t m_memory_count; - std::vector* m_cues; + std::unique_ptr>> m_cues; rekordbox_anlz_t* m__root; rekordbox_anlz_t::tagged_section_t* m__parent; @@ -996,28 +1208,32 @@ class rekordbox_anlz_t : public kaitai::kstruct { /** * The length of the cue list. */ - uint16_t len_cues() const { return m_len_cues; } + uint16_t num_cues() const { return m_num_cues; } /** * Unsure what this means. */ uint32_t memory_count() const { return m_memory_count; } - std::vector* cues() const { return m_cues; } + std::vector>* cues() const { return m_cues.get(); } rekordbox_anlz_t* _root() const { return m__root; } rekordbox_anlz_t::tagged_section_t* _parent() const { return m__parent; } }; private: - std::string m__unnamed0; + std::string m_magic; uint32_t m_len_header; uint32_t m_len_file; std::string m__unnamed3; - std::vector* m_sections; + std::unique_ptr>> m_sections; rekordbox_anlz_t* m__root; kaitai::kstruct* m__parent; public: - std::string _unnamed0() const { return m__unnamed0; } + + /** + * Identifies this as an analysis file. + */ + std::string magic() const { return m_magic; } /** * The number of bytes of this header section. @@ -1034,7 +1250,7 @@ class rekordbox_anlz_t : public kaitai::kstruct { * The remainder of the file is a sequence of type-tagged sections, * identified by a four-byte magic sequence. */ - std::vector* sections() const { return m_sections; } + std::vector>* sections() const { return m_sections.get(); } rekordbox_anlz_t* _root() const { return m__root; } kaitai::kstruct* _parent() const { return m__parent; } }; diff --git a/src/library/rekordbox/kaitaistructs/rekordbox_anlz.ksy b/src/library/rekordbox/kaitaistructs/rekordbox_anlz.ksy index 15fe3c2d8034..08e97a464560 100644 --- a/src/library/rekordbox/kaitaistructs/rekordbox_anlz.ksy +++ b/src/library/rekordbox/kaitaistructs/rekordbox_anlz.ksy @@ -26,7 +26,9 @@ doc: | doc-ref: https://reverseengineering.stackexchange.com/questions/4311/help-reversing-a-edb-database-file-for-pioneers-rekordbox-software seq: - - contents: "PMAI" + - id: magic + contents: "PMAI" + doc: Identifies this as an analysis file. - id: len_header type: u4 doc: | @@ -52,7 +54,7 @@ types: seq: - id: fourcc type: s4 - # enum: section_tags Can't use this until enums support default/unmatched value + enum: section_tags doc: | A tag value indicating what kind of section this is. - id: len_header @@ -68,17 +70,17 @@ types: type: switch-on: fourcc cases: - 0x50434f32: cue_extended_tag #'section_tags::cues_2' (PCO2) - 0x50434f42: cue_tag #'section_tags::cues' (PCOB) - 0x50505448: path_tag #'section_tags::path' (PPTH) - 0x5051545a: beat_grid_tag #'section_tags::beat_grid' (PQTZ) - 0x50564252: vbr_tag #'section_tags::vbr' (PVBR) - 0x50574156: wave_preview_tag #'section_tags::wave_preview' (PWAV) - 0x50575632: wave_preview_tag #'section_tags::wave_tiny' (PWV2) - 0x50575633: wave_scroll_tag #'section_tags::wave_scroll' (PWV3, seen in .EXT) - 0x50575634: wave_color_preview_tag #'section_tags::wave_color_preview' (PWV4, in .EXT) - 0x50575635: wave_color_scroll_tag #'section_tags::wave_color_scroll' (PWV5, in .EXT) - 0x50535349: song_structure_tag #'section_tags::song_structure' (PSSI, in .EXT) + 'section_tags::cues_2': cue_extended_tag # PCO2 + 'section_tags::cues': cue_tag # PCOB + 'section_tags::path': path_tag # PPTH + 'section_tags::beat_grid': beat_grid_tag # PQTZ + 'section_tags::vbr': vbr_tag # PVBR + 'section_tags::wave_preview': wave_preview_tag # PWAV + 'section_tags::wave_tiny': wave_preview_tag # PWV2 + 'section_tags::wave_scroll': wave_scroll_tag # PWV3, seen in .EXT + 'section_tags::wave_color_preview': wave_color_preview_tag # PWV4, in .EXT + 'section_tags::wave_color_scroll': wave_color_scroll_tag # PWV5, in .EXT + 'section_tags::song_structure': song_structure_tag # PSSI, in .EXT _: unknown_tag -webide-representation: '{fourcc}' @@ -91,14 +93,14 @@ types: seq: - type: u4 - type: u4 # @flesniak says this is always 0x80000 - - id: len_beats + - id: num_beats type: u4 doc: | The number of beat entries which follow. - id: beats type: beat_grid_beat repeat: expr - repeat-expr: len_beats + repeat-expr: num_beats doc: The entries of the beat grid. beat_grid_beat: @@ -132,7 +134,7 @@ types: doc: | Identifies whether this tag stores ordinary or hot cues. - size: 2 - - id: len_cues + - id: num_cues type: u2 doc: | The length of the cue list. @@ -143,13 +145,15 @@ types: - id: cues type: cue_entry repeat: expr - repeat-expr: len_cues + repeat-expr: num_cues cue_entry: doc: | A cue list entry. Can either represent a memory cue or a loop. seq: - - contents: "PCPT" + - id: magic + contents: "PCPT" + doc: Identifies this as a cue list entry (cue point). - id: len_header type: u4 - id: len_entry @@ -163,7 +167,7 @@ types: type: u4 enum: cue_entry_status doc: | - If zero, this entry should be ignored. + Indicates if this is an active loop. - type: u4 # Seems to always be 0x10000 - id: order_first type: u2 @@ -203,7 +207,7 @@ types: enum: cue_list_type doc: | Identifies whether this tag stores ordinary or hot cues. - - id: len_cues + - id: num_cues type: u2 doc: | The length of the cue comment list. @@ -211,14 +215,16 @@ types: - id: cues type: cue_extended_entry repeat: expr - repeat-expr: len_cues + repeat-expr: num_cues cue_extended_entry: doc: | A cue extended list entry. Can either describe a memory cue or a loop. seq: - - contents: "PCP2" + - id: magic + contents: "PCP2" + doc: Identifies this as an extended cue list entry (cue point). - id: len_header type: u4 - id: len_entry @@ -232,7 +238,7 @@ types: type: u1 enum: cue_entry_type doc: | - Indicates whether this is a memory cue or a loop. + Indicates whether this is a regular cue point or a loop. - size: 3 # seems to always be 1000 - id: time type: u4 @@ -247,8 +253,19 @@ types: - id: color_id type: u1 doc: | - Color ID of memory cues and loops, same color IDs as track colors - - size: 11 # Loops seem to have some non-zero values in the last four bytes of this. + References a row in the colors table if this is a memory cue or loop + and has been assigned a color. + - size: 7 + - id: loop_numerator + type: u2 + doc: | + The numerator of the loop length in beats. + Zero if the loop is not quantized. + - id: loop_denominator + type: u2 + doc: | + The denominator of the loop length in beats. + Zero if the loop is not quantized. - id: len_comment type: u4 if: len_entry > 43 @@ -262,22 +279,22 @@ types: - id: color_code type: u1 doc: | - A lookup value for a color table? We use this to index to the colors shown in rekordbox. + A lookup value for a color table? We use this to index to the hot cue colors shown in rekordbox. if: (len_entry - len_comment) > 44 - id: color_red type: u1 doc: | - The red component of the color to be displayed. + The red component of the hot cue color to be displayed. if: (len_entry - len_comment) > 45 - id: color_green type: u1 doc: | - The green component of the color to be displayed. + The green component of the hot cue color to be displayed. if: (len_entry - len_comment) > 46 - id: color_blue type: u1 doc: | - The blue component of the color to be displayed. + The blue component of the hot cue color to be displayed. if: (len_entry - len_comment) > 47 - size: len_entry - 48 - len_comment # The remainder after the color if: (len_entry - len_comment) > 48 @@ -294,6 +311,7 @@ types: size: len_path - 2 encoding: utf-16be if: len_path > 1 + -webide-representation: '{path}' vbr_tag: doc: | @@ -311,7 +329,7 @@ types: Stores a waveform preview image suitable for display above the touch strip for jumping to a track position. seq: - - id: len_preview + - id: len_data type: u4 doc: | The length, in bytes, of the preview data itself. This is @@ -319,7 +337,7 @@ types: length of the tag. - type: u4 # This seems to always have the value 0x10000 - id: data - size: len_preview + size: len_data doc: | The actual bytes of the waveform preview. if: _parent.len_tag > _parent.len_header @@ -393,17 +411,46 @@ types: type: u2 doc: | The number of phrases. - - id: style + - id: body + type: song_structure_body + doc: | + The rest of the tag, which needs to be unmasked before it + can be parsed. + size-eos: true + # NOTE: unmasking is disabled because the C++ backend of kaitai_struct + # doesn't seem to support typecasting as of kaitai version 0.10? + # process: 'xor(is_masked ? mask : [0])' + instances: + c: + value: len_entries + # mask: + # value: | + # [ + # (0xCB+c).as, (0xE1+c).as, (0xEE+c).as, (0xFA+c).as, (0xE5+c).as, (0xEE+c).as, (0xAD+c).as, (0xEE+c).as, + # (0xE9+c).as, (0xD2+c).as, (0xE9+c).as, (0xEB+c).as, (0xE1+c).as, (0xE9+c).as, (0xF3+c).as, (0xE8+c).as, + # (0xE9+c).as, (0xF4+c).as, (0xE1+c).as + # ].as + raw_mood: type: u2 - enum: phrase_style - doc: | - The phrase style. 1 is the up-down style - (white label text in rekordbox) where the main phrases consist - of up, down, and chorus. 2 is the bridge-verse style - (black label text in rekordbox) where the main phrases consist - of verse, chorus, and bridge. Style 3 is mostly identical to - bridge-verse style except verses 1-3 are labeled VERSE1 and verses - 4-6 are labeled VERSE2 in rekordbox. + pos: 6 + doc: | + This is a way to tell whether the rest of the tag has been masked. The value is supposed + to range from 1 to 3, but in masked files it will be much larger. + is_masked: + value: 'raw_mood > 20' # This is almost certainly not true for an unmasked file. + -webide-representation: '{body.mood}' + + + song_structure_body: + doc: | + Stores the rest of the song structure tag, which can only be + parsed after unmasking. + seq: + - id: mood + type: u2 + enum: track_mood + doc: | + The mood which rekordbox assigns the track as a whole during phrase analysis. - size: 6 - id: end_beat type: u2 @@ -411,59 +458,104 @@ types: The beat number at which the last phrase ends. The track may continue after the last phrase ends. If this is the case, it will mostly be silence. - - size: 4 + - size: 2 + - id: bank + type: u1 + enum: track_bank + doc: | + The stylistic bank which can be assigned to the track in rekordbox Lighting mode. + - size: 1 - id: entries type: song_structure_entry repeat: expr - repeat-expr: len_entries + repeat-expr: _parent.len_entries song_structure_entry: doc: | A song structure entry, represents a single phrase. seq: - - id: phrase_number + - id: index type: u2 doc: | The absolute number of the phrase, starting at one. - - id: beat_number + - id: beat type: u2 doc: | The beat number at which the phrase starts. - - id: phrase_id + - id: kind type: - switch-on: _parent.style + switch-on: _parent.mood cases: - 'phrase_style::up_down': phrase_up_down - 'phrase_style::verse_bridge': phrase_verse_bridge - _: phrase_verse_bridge + 'track_mood::high': phrase_high + 'track_mood::mid': phrase_mid + 'track_mood::low': phrase_low + _: phrase_mid # We don't recognize this mood, so pick a generic interpretation. + doc: | + The kind of phrase as displayed in rekordbox. + - size: 1 + - id: k1 + type: u1 + doc: One of three flags that identify phrase kind variants in high-mood tracks. + - size: 1 + - id: k2 + type: u1 + doc: One of three flags that identify phrase kind variants in high-mood tracks. + - size: 1 + - id: b + type: u1 + doc: | + Flags how many more beat numbers are in a high-mood "Up 3" phrase. + - id: beat2 + type: u2 + doc: | + Extra beat number (falling within phrase) always present in high-mood "Up 3" phrases. + - id: beat3 + type: u2 + doc: | + Extra beat number (falling within phrase, larger than beat2) + present in high-mood "Up 3" phrases when b has value 1. + - id: beat4 + type: u2 doc: | - Identifier of the phrase label. - - size: _parent.len_entry_bytes - 9 - - id: fill_in + Extra beat number (falling within phrase, larger than beat3) + present in high-mood "Up 3" phrases when b has value 1. + - size: 1 + - id: k3 + type: u1 + doc: One of three flags that identify phrase kind variants in high-mood tracks. + - size: 1 + - id: fill type: u1 doc: | - If nonzero, fill-in is present. - - id: fill_in_beat_number + If nonzero, fill-in is present at end of phrase. + - id: beat_fill type: u2 doc: | The beat number at which fill-in starts. + -webide-representation: '{kind.id}' - phrase_up_down: + phrase_high: seq: - id: id type: u2 - enum: phrase_up_down_id + enum: mood_high_phrase - phrase_verse_bridge: + phrase_mid: seq: - id: id type: u2 - enum: phrase_verse_bridge_id + enum: mood_mid_phrase + + phrase_low: + seq: + - id: id + type: u2 + enum: mood_low_phrase unknown_tag: {} enums: - section_tags: # We can't use this enum until KSC supports default/unmatched values + section_tags: 0x50434f42: cues # PCOB 0x50434f32: cues_2 # PCO2 (seen in .EXT) 0x50505448: path # PPTH @@ -487,27 +579,51 @@ enums: cue_entry_status: 0: disabled 1: enabled + 4: active_loop - phrase_style: - 1: up_down - 2: verse_bridge - 3: verse_bridge_2 + track_mood: + 1: high + 2: mid + 3: low - phrase_verse_bridge_id: + mood_low_phrase: 1: intro - 2: verse1 - 3: verse2 - 4: verse3 - 5: verse4 - 6: verse5 - 7: verse6 + 2: verse_1 + 3: verse_1b # Just displayed as "Verse 1" in rekordbox. + 4: verse_1c # Just displayed as "Verse 1" in rekordbox. + 5: verse_2 + 6: verse_2b # Just displayed as "Verse 2" in rekordbox. + 7: verse_2c # Just displayed as "Verse 2" in rekordbox. 8: bridge 9: chorus 10: outro - phrase_up_down_id: + mood_mid_phrase: + 1: intro + 2: verse_1 + 3: verse_2 + 4: verse_3 + 5: verse_4 + 6: verse_5 + 7: verse_6 + 8: bridge + 9: chorus + 10: outro + + mood_high_phrase: 1: intro 2: up 3: down 5: chorus 6: outro + + track_bank: + 0: default + 1: cool + 2: natural + 3: hot + 4: subtle + 5: warm + 6: vivid + 7: club_1 + 8: club_2 diff --git a/src/library/rekordbox/kaitaistructs/rekordbox_pdb.cpp b/src/library/rekordbox/kaitaistructs/rekordbox_pdb.cpp index 6ad2d48c0649..50448f6b90e5 100644 --- a/src/library/rekordbox/kaitaistructs/rekordbox_pdb.cpp +++ b/src/library/rekordbox/kaitaistructs/rekordbox_pdb.cpp @@ -2,11 +2,12 @@ #include "rekordbox_pdb.h" - +#include "kaitai/exceptions.h" rekordbox_pdb_t::rekordbox_pdb_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = this; + m_tables = nullptr; _read(); } @@ -17,20 +18,27 @@ void rekordbox_pdb_t::_read() { m_next_unused_page = m__io->read_u4le(); m__unnamed4 = m__io->read_u4le(); m_sequence = m__io->read_u4le(); - m__unnamed6 = m__io->ensure_fixed_contents(std::string("\x00\x00\x00\x00", 4)); - int l_tables = num_tables(); - m_tables = new std::vector(); - m_tables->reserve(l_tables); + m_gap = m__io->read_bytes(4); + if (!(gap() == std::string("\x00\x00\x00\x00", 4))) { + throw kaitai::validation_not_equal_error( + std::string("\x00\x00\x00\x00", 4), + gap(), + _io(), + std::string("/seq/6")); + } + m_tables = std::unique_ptr>>( + new std::vector>()); + const int l_tables = num_tables(); for (int i = 0; i < l_tables; i++) { - m_tables->push_back(new table_t(m__io, this, m__root)); + m_tables->push_back(std::move(std::unique_ptr(new table_t(m__io, this, m__root)))); } } rekordbox_pdb_t::~rekordbox_pdb_t() { - for (std::vector::iterator it = m_tables->begin(); it != m_tables->end(); ++it) { - delete *it; - } - delete m_tables; + _clean_up(); +} + +void rekordbox_pdb_t::_clean_up() { } rekordbox_pdb_t::device_sql_string_t::device_sql_string_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { @@ -43,27 +51,58 @@ void rekordbox_pdb_t::device_sql_string_t::_read() { m_length_and_kind = m__io->read_u1(); switch (length_and_kind()) { case 64: { - m_body = new device_sql_long_ascii_t(m__io, this, m__root); + m_body = std::unique_ptr( + new device_sql_long_ascii_t(m__io, this, m__root)); break; } case 144: { - m_body = new device_sql_long_utf16be_t(m__io, this, m__root); + m_body = std::unique_ptr( + new device_sql_long_utf16le_t(m__io, this, m__root)); break; } default: { - m_body = new device_sql_short_ascii_t(length_and_kind(), m__io, this, m__root); + m_body = std::unique_ptr( + new device_sql_short_ascii_t( + length_and_kind(), m__io, this, m__root)); break; } } } rekordbox_pdb_t::device_sql_string_t::~device_sql_string_t() { - delete m_body; + _clean_up(); +} + +void rekordbox_pdb_t::device_sql_string_t::_clean_up() { +} + +rekordbox_pdb_t::history_playlist_row_t::history_playlist_row_t( + kaitai::kstream* p__io, + rekordbox_pdb_t::row_ref_t* p__parent, + rekordbox_pdb_t* p__root) + : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_name = nullptr; + _read(); +} + +void rekordbox_pdb_t::history_playlist_row_t::_read() { + m_id = m__io->read_u4le(); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); +} + +rekordbox_pdb_t::history_playlist_row_t::~history_playlist_row_t() { + _clean_up(); +} + +void rekordbox_pdb_t::history_playlist_row_t::_clean_up() { } rekordbox_pdb_t::playlist_tree_row_t::playlist_tree_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; f_is_folder = false; _read(); } @@ -74,11 +113,14 @@ void rekordbox_pdb_t::playlist_tree_row_t::_read() { m_sort_order = m__io->read_u4le(); m_id = m__io->read_u4le(); m_raw_is_folder = m__io->read_u4le(); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); } rekordbox_pdb_t::playlist_tree_row_t::~playlist_tree_row_t() { - delete m_name; + _clean_up(); +} + +void rekordbox_pdb_t::playlist_tree_row_t::_clean_up() { } bool rekordbox_pdb_t::playlist_tree_row_t::is_folder() { @@ -92,6 +134,7 @@ bool rekordbox_pdb_t::playlist_tree_row_t::is_folder() { rekordbox_pdb_t::color_row_t::color_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; _read(); } @@ -99,38 +142,44 @@ void rekordbox_pdb_t::color_row_t::_read() { m__unnamed0 = m__io->read_bytes(5); m_id = m__io->read_u2le(); m__unnamed2 = m__io->read_u1(); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); } rekordbox_pdb_t::color_row_t::~color_row_t() { - delete m_name; + _clean_up(); +} + +void rekordbox_pdb_t::color_row_t::_clean_up() { } -rekordbox_pdb_t::device_sql_short_ascii_t::device_sql_short_ascii_t(uint8_t p_mangled_length, kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { +rekordbox_pdb_t::device_sql_short_ascii_t::device_sql_short_ascii_t( + uint8_t p_length_and_kind, + kaitai::kstream* p__io, + rekordbox_pdb_t::device_sql_string_t* p__parent, + rekordbox_pdb_t* p__root) + : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - m_mangled_length = p_mangled_length; + m_length_and_kind = p_length_and_kind; f_length = false; _read(); } void rekordbox_pdb_t::device_sql_short_ascii_t::_read() { - n_text = true; - if ( ((kaitai::kstream::mod(mangled_length(), 2) > 0) && (length() >= 0)) ) { - n_text = false; - m_text = kaitai::kstream::bytes_to_str(m__io->read_bytes(length()), std::string("ascii")); - } + m_text = kaitai::kstream::bytes_to_str(m__io->read_bytes((length() - 1)), std::string("ASCII")); } rekordbox_pdb_t::device_sql_short_ascii_t::~device_sql_short_ascii_t() { - if (!n_text) { - } + _clean_up(); +} + +void rekordbox_pdb_t::device_sql_short_ascii_t::_clean_up() { } int32_t rekordbox_pdb_t::device_sql_short_ascii_t::length() { if (f_length) return m_length; - m_length = (((mangled_length() - 1) / 2) - 1); + m_length = (length_and_kind() >> 1); f_length = true; return m_length; } @@ -138,6 +187,7 @@ int32_t rekordbox_pdb_t::device_sql_short_ascii_t::length() { rekordbox_pdb_t::album_row_t::album_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; f_name = false; _read(); } @@ -154,27 +204,32 @@ void rekordbox_pdb_t::album_row_t::_read() { } rekordbox_pdb_t::album_row_t::~album_row_t() { + _clean_up(); +} + +void rekordbox_pdb_t::album_row_t::_clean_up() { if (f_name) { - delete m_name; } } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::album_row_t::name() { if (f_name) - return m_name; + return m_name.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_name())); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_name = true; - return m_name; + return m_name.get(); } rekordbox_pdb_t::page_t::page_t(kaitai::kstream* p__io, rekordbox_pdb_t::page_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_next_page = nullptr; + m_row_groups = nullptr; f_num_rows = false; - f_num_groups = false; + f_num_row_groups = false; f_row_groups = false; f_heap_pos = false; f_is_data_page = false; @@ -182,10 +237,17 @@ rekordbox_pdb_t::page_t::page_t(kaitai::kstream* p__io, rekordbox_pdb_t::page_re } void rekordbox_pdb_t::page_t::_read() { - m__unnamed0 = m__io->ensure_fixed_contents(std::string("\x00\x00\x00\x00", 4)); + m_gap = m__io->read_bytes(4); + if (!(gap() == std::string("\x00\x00\x00\x00", 4))) { + throw kaitai::validation_not_equal_error( + std::string("\x00\x00\x00\x00", 4), + gap(), + _io(), + std::string("/types/page/seq/0")); + } m_page_index = m__io->read_u4le(); m_type = static_cast(m__io->read_u4le()); - m_next_page = new page_ref_t(m__io, this, m__root); + m_next_page = std::unique_ptr(new page_ref_t(m__io, this, m__root)); m__unnamed4 = m__io->read_u4le(); m__unnamed5 = m__io->read_bytes(4); m_num_rows_small = m__io->read_u1(); @@ -206,14 +268,13 @@ void rekordbox_pdb_t::page_t::_read() { } rekordbox_pdb_t::page_t::~page_t() { - delete m_next_page; + _clean_up(); +} + +void rekordbox_pdb_t::page_t::_clean_up() { if (!n_heap) { } if (f_row_groups && !n_row_groups) { - for (std::vector::iterator it = m_row_groups->begin(); it != m_row_groups->end(); ++it) { - delete *it; - } - delete m_row_groups; } } @@ -225,29 +286,31 @@ uint16_t rekordbox_pdb_t::page_t::num_rows() { return m_num_rows; } -int32_t rekordbox_pdb_t::page_t::num_groups() { - if (f_num_groups) - return m_num_groups; - m_num_groups = (((num_rows() - 1) / 16) + 1); - f_num_groups = true; - return m_num_groups; +int32_t rekordbox_pdb_t::page_t::num_row_groups() { + if (f_num_row_groups) + return m_num_row_groups; + m_num_row_groups = (((num_rows() - 1) / 16) + 1); + f_num_row_groups = true; + return m_num_row_groups; } -std::vector* rekordbox_pdb_t::page_t::row_groups() { +std::vector>* rekordbox_pdb_t::page_t::row_groups() { if (f_row_groups) - return m_row_groups; + return m_row_groups.get(); n_row_groups = true; if (is_data_page()) { n_row_groups = false; - int l_row_groups = num_groups(); - m_row_groups = new std::vector(); - m_row_groups->reserve(l_row_groups); + m_row_groups = + std::unique_ptr>>( + new std::vector>()); + const int l_row_groups = num_row_groups(); for (int i = 0; i < l_row_groups; i++) { - m_row_groups->push_back(new row_group_t(i, m__io, this, m__root)); + m_row_groups->push_back(std::move(std::unique_ptr( + new row_group_t(i, m__io, this, m__root)))); } + f_row_groups = true; } - f_row_groups = true; - return m_row_groups; + return m_row_groups.get(); } int32_t rekordbox_pdb_t::page_t::heap_pos() { @@ -270,6 +333,7 @@ rekordbox_pdb_t::row_group_t::row_group_t(uint16_t p_group_index, kaitai::kstrea m__parent = p__parent; m__root = p__root; m_group_index = p_group_index; + m_rows = nullptr; f_base = false; f_row_present_flags = false; f_rows = false; @@ -280,13 +344,13 @@ void rekordbox_pdb_t::row_group_t::_read() { } rekordbox_pdb_t::row_group_t::~row_group_t() { + _clean_up(); +} + +void rekordbox_pdb_t::row_group_t::_clean_up() { if (f_row_present_flags) { } if (f_rows) { - for (std::vector::iterator it = m_rows->begin(); it != m_rows->end(); ++it) { - delete *it; - } - delete m_rows; } } @@ -309,47 +373,82 @@ uint16_t rekordbox_pdb_t::row_group_t::row_present_flags() { return m_row_present_flags; } -std::vector* rekordbox_pdb_t::row_group_t::rows() { +std::vector>* rekordbox_pdb_t::row_group_t::rows() { if (f_rows) - return m_rows; - int l_rows = ((group_index() < (_parent()->num_groups() - 1)) ? (16) : ((kaitai::kstream::mod((_parent()->num_rows() - 1), 16) + 1))); - m_rows = new std::vector(); - m_rows->reserve(l_rows); + return m_rows.get(); + m_rows = std::unique_ptr>>( + new std::vector>()); + const int l_rows = ((group_index() < (_parent()->num_row_groups() - 1)) + ? (16) + : ((kaitai::kstream::mod((_parent()->num_rows() - 1), 16) + + 1))); for (int i = 0; i < l_rows; i++) { - m_rows->push_back(new row_ref_t(i, m__io, this, m__root)); + m_rows->push_back(std::move(std::unique_ptr( + new row_ref_t(i, m__io, this, m__root)))); } f_rows = true; - return m_rows; + return m_rows.get(); } rekordbox_pdb_t::genre_row_t::genre_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; _read(); } void rekordbox_pdb_t::genre_row_t::_read() { m_id = m__io->read_u4le(); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); } rekordbox_pdb_t::genre_row_t::~genre_row_t() { - delete m_name; + _clean_up(); +} + +void rekordbox_pdb_t::genre_row_t::_clean_up() { +} + +rekordbox_pdb_t::history_entry_row_t::history_entry_row_t( + kaitai::kstream* p__io, + rekordbox_pdb_t::row_ref_t* p__parent, + rekordbox_pdb_t* p__root) + : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void rekordbox_pdb_t::history_entry_row_t::_read() { + m_track_id = m__io->read_u4le(); + m_playlist_id = m__io->read_u4le(); + m_entry_index = m__io->read_u4le(); +} + +rekordbox_pdb_t::history_entry_row_t::~history_entry_row_t() { + _clean_up(); +} + +void rekordbox_pdb_t::history_entry_row_t::_clean_up() { } rekordbox_pdb_t::artwork_row_t::artwork_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_path = nullptr; _read(); } void rekordbox_pdb_t::artwork_row_t::_read() { m_id = m__io->read_u4le(); - m_path = new device_sql_string_t(m__io, this, m__root); + m_path = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); } rekordbox_pdb_t::artwork_row_t::~artwork_row_t() { - delete m_path; + _clean_up(); +} + +void rekordbox_pdb_t::artwork_row_t::_clean_up() { } rekordbox_pdb_t::device_sql_long_ascii_t::device_sql_long_ascii_t(kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { @@ -360,15 +459,21 @@ rekordbox_pdb_t::device_sql_long_ascii_t::device_sql_long_ascii_t(kaitai::kstrea void rekordbox_pdb_t::device_sql_long_ascii_t::_read() { m_length = m__io->read_u2le(); - m_text = kaitai::kstream::bytes_to_str(m__io->read_bytes(length()), std::string("ascii")); + m__unnamed1 = m__io->read_u1(); + m_text = kaitai::kstream::bytes_to_str(m__io->read_bytes((length() - 4)), std::string("ASCII")); } rekordbox_pdb_t::device_sql_long_ascii_t::~device_sql_long_ascii_t() { + _clean_up(); +} + +void rekordbox_pdb_t::device_sql_long_ascii_t::_clean_up() { } rekordbox_pdb_t::artist_row_t::artist_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; f_ofs_name_far = false; f_name = false; _read(); @@ -383,10 +488,13 @@ void rekordbox_pdb_t::artist_row_t::_read() { } rekordbox_pdb_t::artist_row_t::~artist_row_t() { + _clean_up(); +} + +void rekordbox_pdb_t::artist_row_t::_clean_up() { if (f_ofs_name_far && !n_ofs_name_far) { } if (f_name) { - delete m_name; } } @@ -400,25 +508,27 @@ uint16_t rekordbox_pdb_t::artist_row_t::ofs_name_far() { m__io->seek((_parent()->row_base() + 10)); m_ofs_name_far = m__io->read_u2le(); m__io->seek(_pos); + f_ofs_name_far = true; } - f_ofs_name_far = true; return m_ofs_name_far; } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::artist_row_t::name() { if (f_name) - return m_name; + return m_name.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ((subtype() == 100) ? (ofs_name_far()) : (ofs_name_near())))); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_name = true; - return m_name; + return m_name.get(); } rekordbox_pdb_t::page_ref_t::page_ref_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_body = nullptr; + m__io__raw_body = nullptr; f_body = false; _read(); } @@ -428,48 +538,57 @@ void rekordbox_pdb_t::page_ref_t::_read() { } rekordbox_pdb_t::page_ref_t::~page_ref_t() { + _clean_up(); +} + +void rekordbox_pdb_t::page_ref_t::_clean_up() { if (f_body) { - delete m__io__raw_body; - delete m_body; } } rekordbox_pdb_t::page_t* rekordbox_pdb_t::page_ref_t::body() { if (f_body) - return m_body; + return m_body.get(); kaitai::kstream *io = _root()->_io(); std::streampos _pos = io->pos(); io->seek((_root()->len_page() * index())); m__raw_body = io->read_bytes(_root()->len_page()); - m__io__raw_body = new kaitai::kstream(m__raw_body); - m_body = new page_t(m__io__raw_body, this, m__root); + m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr(new page_t(m__io__raw_body.get(), this, m__root)); io->seek(_pos); f_body = true; - return m_body; -} - -rekordbox_pdb_t::device_sql_long_utf16be_t::device_sql_long_utf16be_t(kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { - m__parent = p__parent; - m__root = p__root; - _read(); -} - -void rekordbox_pdb_t::device_sql_long_utf16be_t::_read() { - m_length = m__io->read_u2le(); - m_text = kaitai::kstream::bytes_to_str(m__io->read_bytes((length() - 4)), std::string("utf-16be")); -} - -rekordbox_pdb_t::device_sql_long_utf16be_t::~device_sql_long_utf16be_t() { + return m_body.get(); } rekordbox_pdb_t::track_row_t::track_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_ofs_strings = nullptr; + m_unknown_string_8 = nullptr; + m_unknown_string_6 = nullptr; + m_analyze_date = nullptr; + m_file_path = nullptr; + m_date_added = nullptr; + m_unknown_string_3 = nullptr; + m_texter = nullptr; + m_kuvo_public = nullptr; + m_mix_name = nullptr; + m_unknown_string_5 = nullptr; + m_unknown_string_4 = nullptr; + m_message = nullptr; + m_unknown_string_2 = nullptr; + m_isrc = nullptr; + m_unknown_string_7 = nullptr; + m_filename = nullptr; + m_analyze_path = nullptr; + m_comment = nullptr; + m_release_date = nullptr; + m_autoload_hot_cues = nullptr; + m_title = nullptr; f_unknown_string_8 = false; f_unknown_string_6 = false; f_analyze_date = false; f_file_path = false; - f_autoload_hotcues = false; f_date_added = false; f_unknown_string_3 = false; f_texter = false; @@ -479,12 +598,13 @@ rekordbox_pdb_t::track_row_t::track_row_t(kaitai::kstream* p__io, rekordbox_pdb_ f_unknown_string_4 = false; f_message = false; f_unknown_string_2 = false; - f_unknown_string_1 = false; + f_isrc = false; f_unknown_string_7 = false; f_filename = false; f_analyze_path = false; f_comment = false; f_release_date = false; + f_autoload_hot_cues = false; f_title = false; _read(); } @@ -521,326 +641,327 @@ void rekordbox_pdb_t::track_row_t::_read() { m_rating = m__io->read_u1(); m__unnamed29 = m__io->read_u2le(); m__unnamed30 = m__io->read_u2le(); - int l_ofs_strings = 21; - m_ofs_strings = new std::vector(); - m_ofs_strings->reserve(l_ofs_strings); + m_ofs_strings = std::unique_ptr>(new std::vector()); + const int l_ofs_strings = 21; for (int i = 0; i < l_ofs_strings; i++) { - m_ofs_strings->push_back(m__io->read_u2le()); + m_ofs_strings->push_back(std::move(m__io->read_u2le())); } } rekordbox_pdb_t::track_row_t::~track_row_t() { - delete m_ofs_strings; + _clean_up(); +} + +void rekordbox_pdb_t::track_row_t::_clean_up() { if (f_unknown_string_8) { - delete m_unknown_string_8; } if (f_unknown_string_6) { - delete m_unknown_string_6; } if (f_analyze_date) { - delete m_analyze_date; } if (f_file_path) { - delete m_file_path; - } - if (f_autoload_hotcues) { - delete m_autoload_hotcues; } if (f_date_added) { - delete m_date_added; } if (f_unknown_string_3) { - delete m_unknown_string_3; } if (f_texter) { - delete m_texter; } if (f_kuvo_public) { - delete m_kuvo_public; } if (f_mix_name) { - delete m_mix_name; } if (f_unknown_string_5) { - delete m_unknown_string_5; } if (f_unknown_string_4) { - delete m_unknown_string_4; } if (f_message) { - delete m_message; } if (f_unknown_string_2) { - delete m_unknown_string_2; } - if (f_unknown_string_1) { - delete m_unknown_string_1; + if (f_isrc) { } if (f_unknown_string_7) { - delete m_unknown_string_7; } if (f_filename) { - delete m_filename; } if (f_analyze_path) { - delete m_analyze_path; } if (f_comment) { - delete m_comment; } if (f_release_date) { - delete m_release_date; + } + if (f_autoload_hot_cues) { } if (f_title) { - delete m_title; } } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_8() { if (f_unknown_string_8) - return m_unknown_string_8; + return m_unknown_string_8.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(18))); - m_unknown_string_8 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_8 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_8 = true; - return m_unknown_string_8; + return m_unknown_string_8.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_6() { if (f_unknown_string_6) - return m_unknown_string_6; + return m_unknown_string_6.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(9))); - m_unknown_string_6 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_6 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_6 = true; - return m_unknown_string_6; + return m_unknown_string_6.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::analyze_date() { if (f_analyze_date) - return m_analyze_date; + return m_analyze_date.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(15))); - m_analyze_date = new device_sql_string_t(m__io, this, m__root); + m_analyze_date = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_analyze_date = true; - return m_analyze_date; + return m_analyze_date.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::file_path() { if (f_file_path) - return m_file_path; + return m_file_path.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(20))); - m_file_path = new device_sql_string_t(m__io, this, m__root); + m_file_path = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_file_path = true; - return m_file_path; -} - -rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::autoload_hotcues() { - if (f_autoload_hotcues) - return m_autoload_hotcues; - std::streampos _pos = m__io->pos(); - m__io->seek((_parent()->row_base() + ofs_strings()->at(7))); - m_autoload_hotcues = new device_sql_string_t(m__io, this, m__root); - m__io->seek(_pos); - f_autoload_hotcues = true; - return m_autoload_hotcues; + return m_file_path.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::date_added() { if (f_date_added) - return m_date_added; + return m_date_added.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(10))); - m_date_added = new device_sql_string_t(m__io, this, m__root); + m_date_added = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_date_added = true; - return m_date_added; + return m_date_added.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_3() { if (f_unknown_string_3) - return m_unknown_string_3; + return m_unknown_string_3.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(3))); - m_unknown_string_3 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_3 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_3 = true; - return m_unknown_string_3; + return m_unknown_string_3.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::texter() { if (f_texter) - return m_texter; + return m_texter.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(1))); - m_texter = new device_sql_string_t(m__io, this, m__root); + m_texter = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_texter = true; - return m_texter; + return m_texter.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::kuvo_public() { if (f_kuvo_public) - return m_kuvo_public; + return m_kuvo_public.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(6))); - m_kuvo_public = new device_sql_string_t(m__io, this, m__root); + m_kuvo_public = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_kuvo_public = true; - return m_kuvo_public; + return m_kuvo_public.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::mix_name() { if (f_mix_name) - return m_mix_name; + return m_mix_name.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(12))); - m_mix_name = new device_sql_string_t(m__io, this, m__root); + m_mix_name = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_mix_name = true; - return m_mix_name; + return m_mix_name.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_5() { if (f_unknown_string_5) - return m_unknown_string_5; + return m_unknown_string_5.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(8))); - m_unknown_string_5 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_5 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_5 = true; - return m_unknown_string_5; + return m_unknown_string_5.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_4() { if (f_unknown_string_4) - return m_unknown_string_4; + return m_unknown_string_4.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(4))); - m_unknown_string_4 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_4 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_4 = true; - return m_unknown_string_4; + return m_unknown_string_4.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::message() { if (f_message) - return m_message; + return m_message.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(5))); - m_message = new device_sql_string_t(m__io, this, m__root); + m_message = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_message = true; - return m_message; + return m_message.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_2() { if (f_unknown_string_2) - return m_unknown_string_2; + return m_unknown_string_2.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(2))); - m_unknown_string_2 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_2 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_2 = true; - return m_unknown_string_2; + return m_unknown_string_2.get(); } -rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_1() { - if (f_unknown_string_1) - return m_unknown_string_1; +rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::isrc() { + if (f_isrc) + return m_isrc.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(0))); - m_unknown_string_1 = new device_sql_string_t(m__io, this, m__root); + m_isrc = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); - f_unknown_string_1 = true; - return m_unknown_string_1; + f_isrc = true; + return m_isrc.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::unknown_string_7() { if (f_unknown_string_7) - return m_unknown_string_7; + return m_unknown_string_7.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(13))); - m_unknown_string_7 = new device_sql_string_t(m__io, this, m__root); + m_unknown_string_7 = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_unknown_string_7 = true; - return m_unknown_string_7; + return m_unknown_string_7.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::filename() { if (f_filename) - return m_filename; + return m_filename.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(19))); - m_filename = new device_sql_string_t(m__io, this, m__root); + m_filename = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_filename = true; - return m_filename; + return m_filename.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::analyze_path() { if (f_analyze_path) - return m_analyze_path; + return m_analyze_path.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(14))); - m_analyze_path = new device_sql_string_t(m__io, this, m__root); + m_analyze_path = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_analyze_path = true; - return m_analyze_path; + return m_analyze_path.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::comment() { if (f_comment) - return m_comment; + return m_comment.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(16))); - m_comment = new device_sql_string_t(m__io, this, m__root); + m_comment = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_comment = true; - return m_comment; + return m_comment.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::release_date() { if (f_release_date) - return m_release_date; + return m_release_date.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(11))); - m_release_date = new device_sql_string_t(m__io, this, m__root); + m_release_date = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_release_date = true; - return m_release_date; + return m_release_date.get(); +} + +rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::autoload_hot_cues() { + if (f_autoload_hot_cues) + return m_autoload_hot_cues.get(); + std::streampos _pos = m__io->pos(); + m__io->seek((_parent()->row_base() + ofs_strings()->at(7))); + m_autoload_hot_cues = std::unique_ptr( + new device_sql_string_t(m__io, this, m__root)); + m__io->seek(_pos); + f_autoload_hot_cues = true; + return m_autoload_hot_cues.get(); } rekordbox_pdb_t::device_sql_string_t* rekordbox_pdb_t::track_row_t::title() { if (f_title) - return m_title; + return m_title.get(); std::streampos _pos = m__io->pos(); m__io->seek((_parent()->row_base() + ofs_strings()->at(17))); - m_title = new device_sql_string_t(m__io, this, m__root); + m_title = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); m__io->seek(_pos); f_title = true; - return m_title; + return m_title.get(); } rekordbox_pdb_t::key_row_t::key_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; _read(); } void rekordbox_pdb_t::key_row_t::_read() { m_id = m__io->read_u4le(); m_id2 = m__io->read_u4le(); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); } rekordbox_pdb_t::key_row_t::~key_row_t() { - delete m_name; + _clean_up(); +} + +void rekordbox_pdb_t::key_row_t::_clean_up() { } rekordbox_pdb_t::playlist_entry_row_t::playlist_entry_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { @@ -856,39 +977,75 @@ void rekordbox_pdb_t::playlist_entry_row_t::_read() { } rekordbox_pdb_t::playlist_entry_row_t::~playlist_entry_row_t() { + _clean_up(); +} + +void rekordbox_pdb_t::playlist_entry_row_t::_clean_up() { } rekordbox_pdb_t::label_row_t::label_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_name = nullptr; _read(); } void rekordbox_pdb_t::label_row_t::_read() { m_id = m__io->read_u4le(); - m_name = new device_sql_string_t(m__io, this, m__root); + m_name = std::unique_ptr(new device_sql_string_t(m__io, this, m__root)); } rekordbox_pdb_t::label_row_t::~label_row_t() { - delete m_name; + _clean_up(); +} + +void rekordbox_pdb_t::label_row_t::_clean_up() { +} + +rekordbox_pdb_t::device_sql_long_utf16le_t::device_sql_long_utf16le_t( + kaitai::kstream* p__io, + rekordbox_pdb_t::device_sql_string_t* p__parent, + rekordbox_pdb_t* p__root) + : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void rekordbox_pdb_t::device_sql_long_utf16le_t::_read() { + m_length = m__io->read_u2le(); + m__unnamed1 = m__io->read_u1(); + m_text = kaitai::kstream::bytes_to_str( + m__io->read_bytes((length() - 4)), std::string("UTF-16LE")); +} + +rekordbox_pdb_t::device_sql_long_utf16le_t::~device_sql_long_utf16le_t() { + _clean_up(); +} + +void rekordbox_pdb_t::device_sql_long_utf16le_t::_clean_up() { } rekordbox_pdb_t::table_t::table_t(kaitai::kstream* p__io, rekordbox_pdb_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_first_page = nullptr; + m_last_page = nullptr; _read(); } void rekordbox_pdb_t::table_t::_read() { m_type = static_cast(m__io->read_u4le()); m_empty_candidate = m__io->read_u4le(); - m_first_page = new page_ref_t(m__io, this, m__root); - m_last_page = new page_ref_t(m__io, this, m__root); + m_first_page = std::unique_ptr(new page_ref_t(m__io, this, m__root)); + m_last_page = std::unique_ptr(new page_ref_t(m__io, this, m__root)); } rekordbox_pdb_t::table_t::~table_t() { - delete m_first_page; - delete m_last_page; + _clean_up(); +} + +void rekordbox_pdb_t::table_t::_clean_up() { } rekordbox_pdb_t::row_ref_t::row_ref_t(uint16_t p_row_index, kaitai::kstream* p__io, rekordbox_pdb_t::row_group_t* p__parent, rekordbox_pdb_t* p__root) : kaitai::kstruct(p__io) { @@ -906,10 +1063,13 @@ void rekordbox_pdb_t::row_ref_t::_read() { } rekordbox_pdb_t::row_ref_t::~row_ref_t() { + _clean_up(); +} + +void rekordbox_pdb_t::row_ref_t::_clean_up() { if (f_ofs_row) { } if (f_body && !n_body) { - delete m_body; } } @@ -942,7 +1102,7 @@ bool rekordbox_pdb_t::row_ref_t::present() { kaitai::kstruct* rekordbox_pdb_t::row_ref_t::body() { if (f_body) - return m_body; + return m_body.get(); n_body = true; if (present()) { n_body = false; @@ -950,59 +1110,73 @@ kaitai::kstruct* rekordbox_pdb_t::row_ref_t::body() { m__io->seek(row_base()); n_body = true; switch (_parent()->_parent()->type()) { - case PAGE_TYPE_KEYS: { + case rekordbox_pdb_t::PAGE_TYPE_PLAYLIST_TREE: { n_body = false; - m_body = new key_row_t(m__io, this, m__root); + m_body = std::unique_ptr( + new playlist_tree_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_GENRES: { + case rekordbox_pdb_t::PAGE_TYPE_KEYS: { n_body = false; - m_body = new genre_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new key_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_PLAYLIST_ENTRIES: { + case rekordbox_pdb_t::PAGE_TYPE_ARTISTS: { n_body = false; - m_body = new playlist_entry_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new artist_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_TRACKS: { + case rekordbox_pdb_t::PAGE_TYPE_ALBUMS: { n_body = false; - m_body = new track_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new album_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_PLAYLIST_TREE: { + case rekordbox_pdb_t::PAGE_TYPE_GENRES: { n_body = false; - m_body = new playlist_tree_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new genre_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_LABELS: { + case rekordbox_pdb_t::PAGE_TYPE_HISTORY_PLAYLISTS: { n_body = false; - m_body = new label_row_t(m__io, this, m__root); + m_body = std::unique_ptr( + new history_playlist_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_ALBUMS: { + case rekordbox_pdb_t::PAGE_TYPE_ARTWORK: { n_body = false; - m_body = new album_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new artwork_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_COLORS: { + case rekordbox_pdb_t::PAGE_TYPE_PLAYLIST_ENTRIES: { n_body = false; - m_body = new color_row_t(m__io, this, m__root); + m_body = std::unique_ptr( + new playlist_entry_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_ARTISTS: { + case rekordbox_pdb_t::PAGE_TYPE_LABELS: { n_body = false; - m_body = new artist_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new label_row_t(m__io, this, m__root)); break; } - case PAGE_TYPE_ARTWORK: { + case rekordbox_pdb_t::PAGE_TYPE_TRACKS: { n_body = false; - m_body = new artwork_row_t(m__io, this, m__root); + m_body = std::unique_ptr(new track_row_t(m__io, this, m__root)); + break; + } + case rekordbox_pdb_t::PAGE_TYPE_HISTORY_ENTRIES: { + n_body = false; + m_body = std::unique_ptr( + new history_entry_row_t(m__io, this, m__root)); + break; + } + case rekordbox_pdb_t::PAGE_TYPE_COLORS: { + n_body = false; + m_body = std::unique_ptr(new color_row_t(m__io, this, m__root)); break; } } m__io->seek(_pos); + f_body = true; } - f_body = true; - return m_body; + return m_body.get(); } diff --git a/src/library/rekordbox/kaitaistructs/rekordbox_pdb.h b/src/library/rekordbox/kaitaistructs/rekordbox_pdb.h index b8a10f972b97..f408a4e0885c 100644 --- a/src/library/rekordbox/kaitaistructs/rekordbox_pdb.h +++ b/src/library/rekordbox/kaitaistructs/rekordbox_pdb.h @@ -5,10 +5,11 @@ #include "kaitai/kaitaistruct.h" #include +#include #include -#if KAITAI_STRUCT_VERSION < 7000L -#error "Incompatible Kaitai Struct C++/STL API: version 0.7 or later is required" +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" #endif /** @@ -18,18 +19,18 @@ * the Pioneer Professional DJ ecosystem, because it is the format that * their rekordbox software uses to write USB and SD media which can be * mounted in DJ controllers and used to play and mix music. - * + * * It has been reverse-engineered to facilitate sophisticated * integrations with light and laser shows, videos, and other musical * instruments, by supporting deep knowledge of what is playing and * what is coming next through monitoring the network communications of * the players. - * + * * The file is divided into fixed-size blocks. The first block has a * header that establishes the block size, and lists the tables * available in the database, identifying their types and the index of * the first of the series of linked pages that make up that table. - * + * * Each table is made up of a series of rows which may be spread across * any number of pages. The pages start with a header describing the * page and linking to the next page. The rest of the page is used as a @@ -37,25 +38,26 @@ * structure that builds backwards from the end of the page. Each row * of a given type has a fixed size structure which links to any * variable-sized strings by their offsets within the page. - * + * * As changes are made to the table, some records may become unused, * and there may be gaps within the heap that are too small to be used * by other data. There is a bit map in the row index that identifies * which rows are actually present. Rows that are not present must be * ignored: they do not contain valid (or even necessarily well-formed) * data. - * + * * The majority of the work in reverse-engineering this format was * performed by @henrybetts and @flesniak, for which I am hugely * grateful. @GreyCat helped me learn the intricacies (and best * practices) of Kaitai far faster than I would have managed on my own. - * \sa Source + * \sa https://github.com/Deep-Symmetry/crate-digger/blob/master/doc/Analysis.pdf Source */ class rekordbox_pdb_t : public kaitai::kstruct { public: class device_sql_string_t; + class history_playlist_row_t; class playlist_tree_row_t; class color_row_t; class device_sql_short_ascii_t; @@ -63,15 +65,16 @@ class rekordbox_pdb_t : public kaitai::kstruct { class page_t; class row_group_t; class genre_row_t; + class history_entry_row_t; class artwork_row_t; class device_sql_long_ascii_t; class artist_row_t; class page_ref_t; - class device_sql_long_utf16be_t; class track_row_t; class key_row_t; class playlist_entry_row_t; class label_row_t; + class device_sql_long_utf16le_t; class table_t; class row_ref_t; @@ -87,8 +90,8 @@ class rekordbox_pdb_t : public kaitai::kstruct { PAGE_TYPE_PLAYLIST_ENTRIES = 8, PAGE_TYPE_UNKNOWN_9 = 9, PAGE_TYPE_UNKNOWN_10 = 10, - PAGE_TYPE_UNKNOWN_11 = 11, - PAGE_TYPE_UNKNOWN_12 = 12, + PAGE_TYPE_HISTORY_PLAYLISTS = 11, + PAGE_TYPE_HISTORY_ENTRIES = 12, PAGE_TYPE_ARTWORK = 13, PAGE_TYPE_UNKNOWN_14 = 14, PAGE_TYPE_UNKNOWN_15 = 15, @@ -98,10 +101,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { PAGE_TYPE_HISTORY = 19 }; - rekordbox_pdb_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, rekordbox_pdb_t* p__root = 0); + rekordbox_pdb_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~rekordbox_pdb_t(); @@ -115,17 +119,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - device_sql_string_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, rekordbox_pdb_t* p__root = 0); + device_sql_string_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~device_sql_string_t(); private: uint8_t m_length_and_kind; - kaitai::kstruct* m_body; + std::unique_ptr m_body; rekordbox_pdb_t* m__root; kaitai::kstruct* m__parent; @@ -137,11 +142,51 @@ class rekordbox_pdb_t : public kaitai::kstruct { * follow. */ uint8_t length_and_kind() const { return m_length_and_kind; } - kaitai::kstruct* body() const { return m_body; } + kaitai::kstruct* body() const { return m_body.get(); } rekordbox_pdb_t* _root() const { return m__root; } kaitai::kstruct* _parent() const { return m__parent; } }; + /** + * A row that holds a history playlist ID and name, linking to + * the track IDs captured during a performance on the player. + */ + + class history_playlist_row_t : public kaitai::kstruct { + + public: + + history_playlist_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~history_playlist_row_t(); + + private: + uint32_t m_id; + std::unique_ptr m_name; + rekordbox_pdb_t* m__root; + rekordbox_pdb_t::row_ref_t* m__parent; + + public: + + /** + * The unique identifier by which this history playlist can + * be requested. + */ + uint32_t id() const { return m_id; } + + /** + * The variable-length string naming the playlist. + */ + device_sql_string_t* name() const { return m_name.get(); } + rekordbox_pdb_t* _root() const { return m__root; } + rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } + }; + /** * A row that holds a playlist name, ID, indication of whether it * is an ordinary playlist or a folder of other playlists, a link @@ -152,10 +197,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - playlist_tree_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + playlist_tree_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~playlist_tree_row_t(); @@ -173,7 +219,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { uint32_t m_sort_order; uint32_t m_id; uint32_t m_raw_is_folder; - device_sql_string_t* m_name; + std::unique_ptr m_name; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -206,7 +252,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { /** * The variable-length string naming the playlist. */ - device_sql_string_t* name() const { return m_name; } + device_sql_string_t* name() const { return m_name.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; @@ -219,10 +265,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - color_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + color_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~color_row_t(); @@ -231,7 +278,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { std::string m__unnamed0; uint16_t m_id; uint8_t m__unnamed2; - device_sql_string_t* m_name; + std::unique_ptr m_name; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -248,7 +295,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { /** * The variable-length string naming the color. */ - device_sql_string_t* name() const { return m_name; } + device_sql_string_t* name() const { return m_name.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; @@ -261,10 +308,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - device_sql_short_ascii_t(uint8_t p_mangled_length, kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + device_sql_short_ascii_t(uint8_t p_length_and_kind, kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~device_sql_short_ascii_t(); @@ -276,19 +324,13 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: /** - * The un-mangled length of the string, in bytes. + * the length extracted of the entire device_sql_short_ascii type */ int32_t length(); private: std::string m_text; - bool n_text; - - public: - bool _is_null_text() { text(); return n_text; }; - - private: - uint8_t m_mangled_length; + uint8_t m_length_and_kind; rekordbox_pdb_t* m__root; rekordbox_pdb_t::device_sql_string_t* m__parent; @@ -303,7 +345,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * Contains the actual length, incremented, doubled, and * incremented again. Go figure. */ - uint8_t mangled_length() const { return m_mangled_length; } + uint8_t length_and_kind() const { return m_length_and_kind; } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::device_sql_string_t* _parent() const { return m__parent; } }; @@ -316,17 +358,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - album_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + album_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~album_row_t(); private: bool f_name; - device_sql_string_t* m_name; + std::unique_ptr m_name; public: @@ -373,7 +416,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { uint32_t _unnamed5() const { return m__unnamed5; } /** - * @flesniak says: "alwayx 0x03, maybe an unindexed empty string" + * @flesniak says: "always 0x03, maybe an unindexed empty string" */ uint8_t _unnamed6() const { return m__unnamed6; } @@ -398,10 +441,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - page_t(kaitai::kstream* p__io, rekordbox_pdb_t::page_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + page_t(kaitai::kstream* p__io, rekordbox_pdb_t::page_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~page_t(); @@ -420,8 +464,8 @@ class rekordbox_pdb_t : public kaitai::kstruct { uint16_t num_rows(); private: - bool f_num_groups; - int32_t m_num_groups; + bool f_num_row_groups; + int32_t m_num_row_groups; public: @@ -430,11 +474,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { * group can hold up to sixteen rows. All but the final one * will hold sixteen rows. */ - int32_t num_groups(); + int32_t num_row_groups(); private: bool f_row_groups; - std::vector* m_row_groups; + std::unique_ptr>> m_row_groups; bool n_row_groups; public: @@ -449,7 +493,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * can hold up to sixteen rows. Non-data pages do not have * actual rows, and attempting to parse them can crash. */ - std::vector* row_groups(); + std::vector>* row_groups(); private: bool f_heap_pos; @@ -466,10 +510,10 @@ class rekordbox_pdb_t : public kaitai::kstruct { bool is_data_page(); private: - std::string m__unnamed0; + std::string m_gap; uint32_t m_page_index; page_type_t m_type; - page_ref_t* m_next_page; + std::unique_ptr m_next_page; uint32_t m__unnamed4; std::string m__unnamed5; uint8_t m_num_rows_small; @@ -493,7 +537,13 @@ class rekordbox_pdb_t : public kaitai::kstruct { rekordbox_pdb_t::page_ref_t* m__parent; public: - std::string _unnamed0() const { return m__unnamed0; } + + /** + * Only exposed until + * https://github.com/kaitai-io/kaitai_struct/issues/825 can be + * fixed. + */ + std::string gap() const { return m_gap; } /** * Matches the index we used to look up the page, sanity check? @@ -509,7 +559,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * Index of the next page containing this type of rows. Points past * the end of the file if there are no more. */ - page_ref_t* next_page() const { return m_next_page; } + page_ref_t* next_page() const { return m_next_page.get(); } /** * @flesniak said: "sequence number (0->1: 8->13, 1->2: 22, 2->3: 27)" @@ -597,10 +647,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - row_group_t(uint16_t p_group_index, kaitai::kstream* p__io, rekordbox_pdb_t::page_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + row_group_t(uint16_t p_group_index, kaitai::kstream* p__io, rekordbox_pdb_t::page_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~row_group_t(); @@ -633,14 +684,14 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_rows; - std::vector* m_rows; + std::unique_ptr>> m_rows; public: /** * The row offsets in this group. */ - std::vector* rows(); + std::vector>* rows(); private: uint16_t m_group_index; @@ -666,17 +717,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - genre_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + genre_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~genre_row_t(); private: uint32_t m_id; - device_sql_string_t* m_name; + std::unique_ptr m_name; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -691,7 +743,51 @@ class rekordbox_pdb_t : public kaitai::kstruct { /** * The variable-length string naming the genre. */ - device_sql_string_t* name() const { return m_name; } + device_sql_string_t* name() const { return m_name.get(); } + rekordbox_pdb_t* _root() const { return m__root; } + rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } + }; + + /** + * A row that associates a track with a position in a history playlist. + */ + + class history_entry_row_t : public kaitai::kstruct { + + public: + + history_entry_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~history_entry_row_t(); + + private: + uint32_t m_track_id; + uint32_t m_playlist_id; + uint32_t m_entry_index; + rekordbox_pdb_t* m__root; + rekordbox_pdb_t::row_ref_t* m__parent; + + public: + + /** + * The track found at this position in the playlist. + */ + uint32_t track_id() const { return m_track_id; } + + /** + * The history playlist to which this entry belongs. + */ + uint32_t playlist_id() const { return m_playlist_id; } + + /** + * The position within the playlist represented by this entry. + */ + uint32_t entry_index() const { return m_entry_index; } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; @@ -705,17 +801,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - artwork_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + artwork_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~artwork_row_t(); private: uint32_t m_id; - device_sql_string_t* m_path; + std::unique_ptr m_path; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -731,29 +828,31 @@ class rekordbox_pdb_t : public kaitai::kstruct { * The variable-length file path string at which the art file * can be found. */ - device_sql_string_t* path() const { return m_path; } + device_sql_string_t* path() const { return m_path.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; /** - * An ASCII-encoded string preceded by a two-byte length field. + * An ASCII-encoded string preceded by a two-byte length field in a four-byte header. */ class device_sql_long_ascii_t : public kaitai::kstruct { public: - device_sql_long_ascii_t(kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + device_sql_long_ascii_t(kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~device_sql_long_ascii_t(); private: uint16_t m_length; + uint8_t m__unnamed1; std::string m_text; rekordbox_pdb_t* m__root; rekordbox_pdb_t::device_sql_string_t* m__parent; @@ -764,6 +863,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * Contains the length of the string in bytes. */ uint16_t length() const { return m_length; } + uint8_t _unnamed1() const { return m__unnamed1; } /** * The content of the string. @@ -781,10 +881,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - artist_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + artist_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~artist_row_t(); @@ -810,7 +911,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_name; - device_sql_string_t* m_name; + std::unique_ptr m_name; public: @@ -871,17 +972,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - page_ref_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, rekordbox_pdb_t* p__root = 0); + page_ref_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~page_ref_t(); private: bool f_body; - page_t* m_body; + std::unique_ptr m_body; public: @@ -896,7 +998,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { rekordbox_pdb_t* m__root; kaitai::kstruct* m__parent; std::string m__raw_body; - kaitai::kstream* m__io__raw_body; + std::unique_ptr m__io__raw_body; public: @@ -907,44 +1009,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { rekordbox_pdb_t* _root() const { return m__root; } kaitai::kstruct* _parent() const { return m__parent; } std::string _raw_body() const { return m__raw_body; } - kaitai::kstream* _io__raw_body() const { return m__io__raw_body; } - }; - - /** - * A UTF-16BE-encoded string preceded by a two-byte length field. - */ - - class device_sql_long_utf16be_t : public kaitai::kstruct { - - public: - - device_sql_long_utf16be_t(kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); - - private: - void _read(); - - public: - ~device_sql_long_utf16be_t(); - - private: - uint16_t m_length; - std::string m_text; - rekordbox_pdb_t* m__root; - rekordbox_pdb_t::device_sql_string_t* m__parent; - - public: - - /** - * Contains the length of the string in bytes, including two trailing nulls. - */ - uint16_t length() const { return m_length; } - - /** - * The content of the string. - */ - std::string text() const { return m_text; } - rekordbox_pdb_t* _root() const { return m__root; } - rekordbox_pdb_t::device_sql_string_t* _parent() const { return m__parent; } + kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); } }; /** @@ -957,17 +1022,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - track_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + track_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~track_row_t(); private: bool f_unknown_string_8; - device_sql_string_t* m_unknown_string_8; + std::unique_ptr m_unknown_string_8; public: @@ -978,7 +1044,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_unknown_string_6; - device_sql_string_t* m_unknown_string_6; + std::unique_ptr m_unknown_string_6; public: @@ -989,7 +1055,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_analyze_date; - device_sql_string_t* m_analyze_date; + std::unique_ptr m_analyze_date; public: @@ -1000,7 +1066,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_file_path; - device_sql_string_t* m_file_path; + std::unique_ptr m_file_path; public: @@ -1009,23 +1075,9 @@ class rekordbox_pdb_t : public kaitai::kstruct { */ device_sql_string_t* file_path(); - private: - bool f_autoload_hotcues; - device_sql_string_t* m_autoload_hotcues; - - public: - - /** - * A string whose value is always either empty or "ON", and - * which apparently for some insane reason is used, rather than - * a single bit somewhere, to control whether hot-cues are - * auto-loaded for the track. - */ - device_sql_string_t* autoload_hotcues(); - private: bool f_date_added; - device_sql_string_t* m_date_added; + std::unique_ptr m_date_added; public: @@ -1036,7 +1088,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_unknown_string_3; - device_sql_string_t* m_unknown_string_3; + std::unique_ptr m_unknown_string_3; public: @@ -1049,18 +1101,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_texter; - device_sql_string_t* m_texter; + std::unique_ptr m_texter; public: /** - * A string of unknown purpose, which @flesnik named. + * A string of unknown purpose, which @flesniak named. */ device_sql_string_t* texter(); private: bool f_kuvo_public; - device_sql_string_t* m_kuvo_public; + std::unique_ptr m_kuvo_public; public: @@ -1074,7 +1126,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_mix_name; - device_sql_string_t* m_mix_name; + std::unique_ptr m_mix_name; public: @@ -1085,7 +1137,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_unknown_string_5; - device_sql_string_t* m_unknown_string_5; + std::unique_ptr m_unknown_string_5; public: @@ -1096,7 +1148,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_unknown_string_4; - device_sql_string_t* m_unknown_string_4; + std::unique_ptr m_unknown_string_4; public: @@ -1109,42 +1161,42 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_message; - device_sql_string_t* m_message; + std::unique_ptr m_message; public: /** - * A string of unknown purpose, which @flesnik named. + * A string of unknown purpose, which @flesniak named. */ device_sql_string_t* message(); private: bool f_unknown_string_2; - device_sql_string_t* m_unknown_string_2; + std::unique_ptr m_unknown_string_2; public: /** * A string of unknown purpose; @flesniak said "thought - * tracknumber -> wrong!" + * track number -> wrong!" */ device_sql_string_t* unknown_string_2(); private: - bool f_unknown_string_1; - device_sql_string_t* m_unknown_string_1; + bool f_isrc; + std::unique_ptr m_isrc; public: /** - * A string of unknown purpose, which has so far only been - * empty. + * International Standard Recording Code of track + * when known (in mangled format). */ - device_sql_string_t* unknown_string_1(); + device_sql_string_t* isrc(); private: bool f_unknown_string_7; - device_sql_string_t* m_unknown_string_7; + std::unique_ptr m_unknown_string_7; public: @@ -1155,7 +1207,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_filename; - device_sql_string_t* m_filename; + std::unique_ptr m_filename; public: @@ -1166,7 +1218,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_analyze_path; - device_sql_string_t* m_analyze_path; + std::unique_ptr m_analyze_path; public: @@ -1180,7 +1232,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_comment; - device_sql_string_t* m_comment; + std::unique_ptr m_comment; public: @@ -1191,7 +1243,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_release_date; - device_sql_string_t* m_release_date; + std::unique_ptr m_release_date; public: @@ -1200,9 +1252,23 @@ class rekordbox_pdb_t : public kaitai::kstruct { */ device_sql_string_t* release_date(); + private: + bool f_autoload_hot_cues; + std::unique_ptr m_autoload_hot_cues; + + public: + + /** + * A string whose value is always either empty or "ON", and + * which apparently for some insane reason is used, rather than + * a single bit somewhere, to control whether hot-cues are + * auto-loaded for the track. + */ + device_sql_string_t* autoload_hot_cues(); + private: bool f_title; - device_sql_string_t* m_title; + std::unique_ptr m_title; public: @@ -1243,7 +1309,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { uint8_t m_rating; uint16_t m__unnamed29; uint16_t m__unnamed30; - std::vector* m_ofs_strings; + std::unique_ptr> m_ofs_strings; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -1422,7 +1488,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * The location, relative to the start of this row, of a * variety of variable-length strings. */ - std::vector* ofs_strings() const { return m_ofs_strings; } + std::vector* ofs_strings() const { return m_ofs_strings.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; @@ -1435,10 +1501,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - key_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + key_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~key_row_t(); @@ -1446,7 +1513,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: uint32_t m_id; uint32_t m_id2; - device_sql_string_t* m_name; + std::unique_ptr m_name; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -1466,7 +1533,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { /** * The variable-length string naming the key. */ - device_sql_string_t* name() const { return m_name; } + device_sql_string_t* name() const { return m_name.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; @@ -1479,10 +1546,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - playlist_entry_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + playlist_entry_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~playlist_entry_row_t(); @@ -1522,17 +1590,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - label_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + label_row_t(kaitai::kstream* p__io, rekordbox_pdb_t::row_ref_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~label_row_t(); private: uint32_t m_id; - device_sql_string_t* m_name; + std::unique_ptr m_name; rekordbox_pdb_t* m__root; rekordbox_pdb_t::row_ref_t* m__parent; @@ -1547,11 +1616,51 @@ class rekordbox_pdb_t : public kaitai::kstruct { /** * The variable-length string naming the label. */ - device_sql_string_t* name() const { return m_name; } + device_sql_string_t* name() const { return m_name.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t::row_ref_t* _parent() const { return m__parent; } }; + /** + * A UTF-16LE-encoded string preceded by a two-byte length field in a four-byte header. + */ + + class device_sql_long_utf16le_t : public kaitai::kstruct { + + public: + + device_sql_long_utf16le_t(kaitai::kstream* p__io, rekordbox_pdb_t::device_sql_string_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~device_sql_long_utf16le_t(); + + private: + uint16_t m_length; + uint8_t m__unnamed1; + std::string m_text; + rekordbox_pdb_t* m__root; + rekordbox_pdb_t::device_sql_string_t* m__parent; + + public: + + /** + * Contains the length of the string in bytes, plus four trailing bytes that must be ignored. + */ + uint16_t length() const { return m_length; } + uint8_t _unnamed1() const { return m__unnamed1; } + + /** + * The content of the string. + */ + std::string text() const { return m_text; } + rekordbox_pdb_t* _root() const { return m__root; } + rekordbox_pdb_t::device_sql_string_t* _parent() const { return m__parent; } + }; + /** * Each table is a linked list of pages containing rows of a single * type. This header describes the nature of the table and links to @@ -1562,10 +1671,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - table_t(kaitai::kstream* p__io, rekordbox_pdb_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + table_t(kaitai::kstream* p__io, rekordbox_pdb_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~table_t(); @@ -1573,8 +1683,8 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: page_type_t m_type; uint32_t m_empty_candidate; - page_ref_t* m_first_page; - page_ref_t* m_last_page; + std::unique_ptr m_first_page; + std::unique_ptr m_last_page; rekordbox_pdb_t* m__root; rekordbox_pdb_t* m__parent; @@ -1592,7 +1702,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * zero rows, but the next page it links to contains the start * of the meaningful data rows. */ - page_ref_t* first_page() const { return m_first_page; } + page_ref_t* first_page() const { return m_first_page.get(); } /** * Holds the index of the last page that makes up this table. @@ -1601,7 +1711,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { * notice that the `next_page` link you followed took you to a * page of a different `type`. */ - page_ref_t* last_page() const { return m_last_page; } + page_ref_t* last_page() const { return m_last_page.get(); } rekordbox_pdb_t* _root() const { return m__root; } rekordbox_pdb_t* _parent() const { return m__parent; } }; @@ -1618,10 +1728,11 @@ class rekordbox_pdb_t : public kaitai::kstruct { public: - row_ref_t(uint16_t p_row_index, kaitai::kstream* p__io, rekordbox_pdb_t::row_group_t* p__parent = 0, rekordbox_pdb_t* p__root = 0); + row_ref_t(uint16_t p_row_index, kaitai::kstream* p__io, rekordbox_pdb_t::row_group_t* p__parent = nullptr, rekordbox_pdb_t* p__root = nullptr); private: void _read(); + void _clean_up(); public: ~row_ref_t(); @@ -1666,7 +1777,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { private: bool f_body; - kaitai::kstruct* m_body; + std::unique_ptr m_body; bool n_body; public: @@ -1705,8 +1816,8 @@ class rekordbox_pdb_t : public kaitai::kstruct { uint32_t m_next_unused_page; uint32_t m__unnamed4; uint32_t m_sequence; - std::string m__unnamed6; - std::vector* m_tables; + std::string m_gap; + std::unique_ptr>> m_tables; rekordbox_pdb_t* m__root; kaitai::kstruct* m__parent; @@ -1735,7 +1846,7 @@ class rekordbox_pdb_t : public kaitai::kstruct { uint32_t num_tables() const { return m_num_tables; } /** - * @flesinak said: "Not used as any `empty_candidate`, points + * @flesniak said: "Not used as any `empty_candidate`, points * past the end of the file." */ uint32_t next_unused_page() const { return m_next_unused_page; } @@ -1746,12 +1857,18 @@ class rekordbox_pdb_t : public kaitai::kstruct { * sometimes by two or three." */ uint32_t sequence() const { return m_sequence; } - std::string _unnamed6() const { return m__unnamed6; } + + /** + * Only exposed until + * https://github.com/kaitai-io/kaitai_struct/issues/825 can be + * fixed. + */ + std::string gap() const { return m_gap; } /** * Describes and links to the tables present in the database. */ - std::vector* tables() const { return m_tables; } + std::vector>* tables() const { return m_tables.get(); } rekordbox_pdb_t* _root() const { return m__root; } kaitai::kstruct* _parent() const { return m__parent; } }; diff --git a/src/library/rekordbox/kaitaistructs/rekordbox_pdb.ksy b/src/library/rekordbox/kaitaistructs/rekordbox_pdb.ksy index ba9eca0a2a43..74311623b90d 100644 --- a/src/library/rekordbox/kaitaistructs/rekordbox_pdb.ksy +++ b/src/library/rekordbox/kaitaistructs/rekordbox_pdb.ksy @@ -70,7 +70,7 @@ seq: - id: next_unused_page type: u4 doc: | - @flesinak said: "Not used as any `empty_candidate`, points + @flesniak said: "Not used as any `empty_candidate`, points past the end of the file." - type: u4 - id: sequence @@ -78,7 +78,12 @@ seq: doc: | @flesniak said: "Always incremented by at least one, sometimes by two or three." - - contents: [0, 0, 0, 0] + - id: gap + contents: [0, 0, 0, 0] + doc: | + Only exposed until + https://github.com/kaitai-io/kaitai_struct/issues/825 can be + fixed. - id: tables type: table repeat: expr @@ -145,7 +150,12 @@ types: an index which locates all rows present in the heap via their offsets past the end of the page header. seq: - - contents: [0, 0, 0, 0] + - id: gap + contents: [0, 0, 0, 0] + doc: | + Only exposed until + https://github.com/kaitai-io/kaitai_struct/issues/825 can be + fixed. - id: page_index doc: Matches the index we used to look up the page, sanity check? type: u4 @@ -230,7 +240,7 @@ types: index entries there are, but some of those may not be marked as present in the table due to deletion). -webide-parse-mode: eager - num_groups: + num_row_groups: value: '(num_rows - 1) / 16 + 1' doc: | The number of row groups that are present in the index. Each @@ -239,7 +249,7 @@ types: row_groups: type: 'row_group(_index)' repeat: expr - repeat-expr: num_groups + repeat-expr: num_row_groups doc: | The actual row groups making up the row index. Each group can hold up to sixteen rows. Non-data pages do not have @@ -276,7 +286,7 @@ types: rows: type: row_ref(_index) repeat: expr - repeat-expr: '(group_index < (_parent.num_groups - 1)) ? 16 : ((_parent.num_rows - 1) % 16 + 1)' + repeat-expr: '(group_index < (_parent.num_row_groups - 1)) ? 16 : ((_parent.num_rows - 1) % 16 + 1)' doc: | The row offsets in this group. @@ -328,6 +338,8 @@ types: 'page_type::labels': label_row 'page_type::playlist_tree': playlist_tree_row 'page_type::playlist_entries': playlist_entry_row + 'page_type::history_playlists': history_playlist_row + 'page_type::history_entries': history_entry_row 'page_type::tracks': track_row if: present doc: | @@ -358,7 +370,7 @@ types: - type: u4 - type: u1 doc: | - @flesniak says: "alwayx 0x03, maybe an unindexed empty string" + @flesniak says: "always 0x03, maybe an unindexed empty string" - id: ofs_name type: u1 doc: | @@ -544,6 +556,38 @@ types: doc: | The playlist to which this entry belongs. + history_playlist_row: + doc: | + A row that holds a history playlist ID and name, linking to + the track IDs captured during a performance on the player. + seq: + - id: id + type: u4 + doc: | + The unique identifier by which this history playlist can + be requested. + - id: name + type: device_sql_string + doc: | + The variable-length string naming the playlist. + + history_entry_row: + doc: | + A row that associates a track with a position in a history playlist. + seq: + - id: track_id + type: u4 + doc: | + The track found at this position in the playlist. + - id: playlist_id + type: u4 + doc: | + The history playlist to which this entry belongs. + - id: entry_index + type: u4 + doc: | + The position within the playlist represented by this entry. + track_row: doc: | A row that describes a track that can be played, with many @@ -687,25 +731,25 @@ types: The location, relative to the start of this row, of a variety of variable-length strings. instances: - unknown_string_1: + isrc: type: device_sql_string pos: _parent.row_base + ofs_strings[0] doc: | - A string of unknown purpose, which has so far only been - empty. + International Standard Recording Code of track + when known (in mangled format). -webide-parse-mode: eager texter: type: device_sql_string pos: _parent.row_base + ofs_strings[1] doc: | - A string of unknown purpose, which @flesnik named. + A string of unknown purpose, which @flesniak named. -webide-parse-mode: eager unknown_string_2: type: device_sql_string pos: _parent.row_base + ofs_strings[2] doc: | A string of unknown purpose; @flesniak said "thought - tracknumber -> wrong!" + track number -> wrong!" unknown_string_3: type: device_sql_string pos: _parent.row_base + ofs_strings[3] @@ -725,7 +769,7 @@ types: type: device_sql_string pos: _parent.row_base + ofs_strings[5] doc: | - A string of unknown purpose, which @flesnik named. + A string of unknown purpose, which @flesniak named. -webide-parse-mode: eager kuvo_public: type: device_sql_string @@ -736,7 +780,7 @@ types: a single bit somewhere, to control whether the track information is visible on Kuvo. -webide-parse-mode: eager - autoload_hotcues: + autoload_hot_cues: type: device_sql_string pos: _parent.row_base + ofs_strings[7] doc: | @@ -843,7 +887,7 @@ types: switch-on: length_and_kind cases: 0x40: device_sql_long_ascii - 0x90: device_sql_long_utf16be + 0x90: device_sql_long_utf16le _: device_sql_short_ascii(length_and_kind) -webide-parse-mode: eager -webide-representation: '{body.text}' @@ -852,7 +896,7 @@ types: doc: | An ASCII-encoded string up to 127 bytes long. params: - - id: mangled_length + - id: length_and_kind type: u1 doc: | Contains the actual length, incremented, doubled, and @@ -860,45 +904,46 @@ types: seq: - id: text type: str - size: length - encoding: ascii - if: '(mangled_length % 2 > 0) and (length >= 0)' # Skip invalid strings + size: length - 1 + encoding: ASCII doc: | The content of the string. instances: length: - value: '((mangled_length - 1) / 2) - 1' + value: '(length_and_kind >> 1)' doc: | - The un-mangled length of the string, in bytes. + the length extracted of the entire device_sql_short_ascii type -webide-parse-mode: eager device_sql_long_ascii: doc: | - An ASCII-encoded string preceded by a two-byte length field. + An ASCII-encoded string preceded by a two-byte length field in a four-byte header. seq: - id: length type: u2 doc: | Contains the length of the string in bytes. + - type: u1 - id: text type: str - size: length - encoding: ascii + size: length - 4 + encoding: ASCII doc: | The content of the string. - device_sql_long_utf16be: + device_sql_long_utf16le: doc: | - A UTF-16BE-encoded string preceded by a two-byte length field. + A UTF-16LE-encoded string preceded by a two-byte length field in a four-byte header. seq: - id: length type: u2 doc: | - Contains the length of the string in bytes, including two trailing nulls. + Contains the length of the string in bytes, plus four trailing bytes that must be ignored. + - type: u1 - id: text type: str size: length - 4 - encoding: utf-16be + encoding: UTF-16LE doc: | The content of the string. @@ -948,11 +993,15 @@ enums: 10: id: unknown_10 11: - id: unknown_11 + id: history_playlists doc: | - The rows all seem to have history file names in them, such as "HISTORY 001". + Holds rows that assign IDs and give names to the history playlists + that have been captured by the player, such as "HISTORY 001". 12: - id: unknown_12 + id: history_entries + doc: | + Holds rows that enumerate the tracks found in history playlists + and the playlists they belong to. 13: id: artwork doc: | @@ -972,4 +1021,4 @@ enums: 19: id: history doc: | - Holds rows listing tracks played in performance sessions. + Holds information to help rekordbox sync history playlists. diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index d8d45020a500..10466f33bb1f 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -274,9 +275,9 @@ QString getText(rekordbox_pdb_t::device_sql_string_t* deviceString) { rekordbox_pdb_t::device_sql_long_ascii_t* longAsciiString = static_cast(deviceString->body()); text = QString::fromStdString(longAsciiString->text()); - } else if (instanceof (deviceString->body())) { - rekordbox_pdb_t::device_sql_long_utf16be_t* longUtf16beString = - static_cast(deviceString->body()); + } else if (instanceof (deviceString->body())) { + rekordbox_pdb_t::device_sql_long_utf16le_t* longUtf16beString = + static_cast(deviceString->body()); text = toUnicode(longUtf16beString->text()); } @@ -490,7 +491,7 @@ QString parseDeviceDB(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dev std::ifstream ifs(dbPath.toStdString(), std::ifstream::binary); kaitai::kstream ks(&ifs); - rekordbox_pdb_t reckordboxDB = rekordbox_pdb_t(&ks); + rekordbox_pdb_t rekordboxDB = rekordbox_pdb_t(&ks); // There are other types of tables (eg. COLOR), these are the only ones we are // interested at the moment. Perhaps when/if @@ -523,70 +524,47 @@ QString parseDeviceDB(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dev bool folderOrPlaylistFound = false; for (int tableOrderIndex = 0; tableOrderIndex < totalTables; tableOrderIndex++) { - for (std::vector::iterator table = - reckordboxDB.tables()->begin(); - table != reckordboxDB.tables()->end(); - ++table) { - if ((*table)->type() == tableOrder[tableOrderIndex]) { - uint16_t lastIndex = (*table)->last_page()->index(); - rekordbox_pdb_t::page_ref_t* currentRef = (*table)->first_page(); + for (const auto& table : *rekordboxDB.tables()) { + if (table->type() == tableOrder[tableOrderIndex]) { + uint16_t lastIndex = table->last_page()->index(); + rekordbox_pdb_t::page_ref_t* currentRef = table->first_page(); while (true) { rekordbox_pdb_t::page_t* page = currentRef->body(); if (page->is_data_page()) { - for (std::vector:: - iterator rowGroup = - page->row_groups()->begin(); - rowGroup != page->row_groups()->end(); - ++rowGroup) { - for (std::vector:: - iterator rowRef = (*rowGroup) - ->rows() - ->begin(); - rowRef != (*rowGroup)->rows()->end(); - ++rowRef) { - if ((*rowRef)->present()) { + for (const auto& rowgroup : *page->row_groups()) { + for (const auto& rowRef : *rowgroup->rows()) { + if (rowRef->present()) { switch (tableOrder[tableOrderIndex]) { case rekordbox_pdb_t::PAGE_TYPE_KEYS: { - // Key found, update map - rekordbox_pdb_t::key_row_t* key = - static_cast( - (*rowRef)->body()); + auto* key = + static_cast( + rowRef->body()); keysMap[key->id()] = getText(key->name()); } break; case rekordbox_pdb_t::PAGE_TYPE_GENRES: { - // Genre found, update map - rekordbox_pdb_t::genre_row_t* genre = - static_cast( - (*rowRef)->body()); + auto* genre = + static_cast( + rowRef->body()); genresMap[genre->id()] = getText(genre->name()); } break; case rekordbox_pdb_t::PAGE_TYPE_ARTISTS: { - // Artist found, update map - rekordbox_pdb_t::artist_row_t* artist = - static_cast( - (*rowRef)->body()); + auto* artist = + static_cast( + rowRef->body()); artistsMap[artist->id()] = getText(artist->name()); } break; case rekordbox_pdb_t::PAGE_TYPE_ALBUMS: { - // Album found, update map - rekordbox_pdb_t::album_row_t* album = - static_cast( - (*rowRef)->body()); + auto* album = + static_cast( + rowRef->body()); albumsMap[album->id()] = getText(album->name()); } break; case rekordbox_pdb_t::PAGE_TYPE_PLAYLIST_ENTRIES: { - // Playlist to track mapping found, update map - rekordbox_pdb_t::playlist_entry_row_t* - playlistEntry = static_cast< - rekordbox_pdb_t:: - playlist_entry_row_t*>( - (*rowRef)->body()); + auto* playlistEntry = + static_cast( + rowRef->body()); playlistTrackMap [playlistEntry->playlist_id()] [playlistEntry->entry_index()] = @@ -594,11 +572,9 @@ QString parseDeviceDB(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dev ->track_id(); } break; case rekordbox_pdb_t::PAGE_TYPE_TRACKS: { - // Track found, insert into database insertTrack(database, - static_cast( - (*rowRef)->body()), + static_cast( + rowRef->body()), query, queryInsertIntoDevicePlaylistTracks, artistsMap, @@ -612,12 +588,9 @@ QString parseDeviceDB(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dev audioFilesCount++; } break; case rekordbox_pdb_t::PAGE_TYPE_PLAYLIST_TREE: { - // Playlist tree node found, update map - rekordbox_pdb_t::playlist_tree_row_t* - playlistTree = static_cast< - rekordbox_pdb_t:: - playlist_tree_row_t*>( - (*rowRef)->body()); + auto* playlistTree = + static_cast( + rowRef->body()); playlistNameMap[playlistTree->id()] = getText(playlistTree->name()); @@ -632,6 +605,8 @@ QString parseDeviceDB(mixxx::DbConnectionPoolPtr dbConnectionPool, TreeItem* dev folderOrPlaylistFound = true; } break; default: + // we currently don't handle any other + // data, even though there is more. break; } } @@ -909,27 +884,21 @@ void readAnalyze(TrackPointer track, QList memoryCuesAndLoops; int lastHotCueIndex = 0; - for (std::vector::iterator section = - anlz.sections()->begin(); - section != anlz.sections()->end(); - ++section) { - switch ((*section)->fourcc()) { + for (const auto& section : *anlz.sections()) { + switch (section->fourcc()) { case rekordbox_anlz_t::SECTION_TAGS_BEAT_GRID: { if (!ignoreCues) { break; } - rekordbox_anlz_t::beat_grid_tag_t* beatGridTag = + auto* beatGridTag = static_cast( - (*section)->body()); + section->body()); QVector beats; - for (std::vector::iterator - beat = beatGridTag->beats()->begin(); - beat != beatGridTag->beats()->end(); - ++beat) { - int time = static_cast((*beat)->time()) - timingOffset; + for (const auto& beat : *beatGridTag->beats()) { + int time = static_cast(beat->time()) - timingOffset; // Ensure no offset times are less than 1 if (time < 1) { time = 1; @@ -948,15 +917,12 @@ void readAnalyze(TrackPointer track, break; } - rekordbox_anlz_t::cue_tag_t* cuesTag = + auto* cuesTag = static_cast( - (*section)->body()); + section->body()); - for (std::vector::iterator - cueEntry = cuesTag->cues()->begin(); - cueEntry != cuesTag->cues()->end(); - ++cueEntry) { - int time = static_cast((*cueEntry)->time()) - timingOffset; + for (const auto& cueEntry : *cuesTag->cues()) { + int time = static_cast(cueEntry->time()) - timingOffset; // Ensure no offset times are less than 1 if (time < 1) { time = 1; @@ -966,7 +932,7 @@ void readAnalyze(TrackPointer track, switch (cuesTag->type()) { case rekordbox_anlz_t::CUE_LIST_TYPE_MEMORY_CUES: { - switch ((*cueEntry)->type()) { + switch (cueEntry->type()) { case rekordbox_anlz_t::CUE_ENTRY_TYPE_MEMORY_CUE: { memory_cue_loop_t memoryCue; memoryCue.startPosition = position; @@ -975,7 +941,7 @@ void readAnalyze(TrackPointer track, memoryCuesAndLoops << memoryCue; } break; case rekordbox_anlz_t::CUE_ENTRY_TYPE_LOOP: { - int endTime = static_cast((*cueEntry)->loop_time()) - timingOffset; + int endTime = static_cast(cueEntry->loop_time()) - timingOffset; // Ensure no offset times are less than 1 if (endTime < 1) { endTime = 1; @@ -991,7 +957,7 @@ void readAnalyze(TrackPointer track, } } break; case rekordbox_anlz_t::CUE_LIST_TYPE_HOT_CUES: { - int hotCueIndex = static_cast((*cueEntry)->hot_cue() - 1); + int hotCueIndex = static_cast(cueEntry->hot_cue() - 1); if (hotCueIndex > lastHotCueIndex) { lastHotCueIndex = hotCueIndex; } @@ -1011,15 +977,12 @@ void readAnalyze(TrackPointer track, break; } - rekordbox_anlz_t::cue_extended_tag_t* cuesExtendedTag = + auto* cuesExtendedTag = static_cast( - (*section)->body()); + section->body()); - for (std::vector::iterator - cueExtendedEntry = cuesExtendedTag->cues()->begin(); - cueExtendedEntry != cuesExtendedTag->cues()->end(); - ++cueExtendedEntry) { - int time = static_cast((*cueExtendedEntry)->time()) - timingOffset; + for (const auto& cueExtendedEntry : *cuesExtendedTag->cues()) { + int time = static_cast(cueExtendedEntry->time()) - timingOffset; // Ensure no offset times are less than 1 if (time < 1) { time = 1; @@ -1029,20 +992,20 @@ void readAnalyze(TrackPointer track, switch (cuesExtendedTag->type()) { case rekordbox_anlz_t::CUE_LIST_TYPE_MEMORY_CUES: { - switch ((*cueExtendedEntry)->type()) { + switch (cueExtendedEntry->type()) { case rekordbox_anlz_t::CUE_ENTRY_TYPE_MEMORY_CUE: { memory_cue_loop_t memoryCue; memoryCue.startPosition = position; memoryCue.endPosition = mixxx::audio::kInvalidFramePos; - memoryCue.comment = toUnicode((*cueExtendedEntry)->comment()); + memoryCue.comment = toUnicode(cueExtendedEntry->comment()); memoryCue.color = colorFromID(static_cast( - (*cueExtendedEntry)->color_id())); + cueExtendedEntry->color_id())); memoryCuesAndLoops << memoryCue; } break; case rekordbox_anlz_t::CUE_ENTRY_TYPE_LOOP: { int endTime = static_cast( - (*cueExtendedEntry)->loop_time()) - + cueExtendedEntry->loop_time()) - timingOffset; // Ensure no offset times are less than 1 if (endTime < 1) { @@ -1053,14 +1016,14 @@ void readAnalyze(TrackPointer track, loop.startPosition = position; loop.endPosition = mixxx::audio::FramePos( sampleRateKhz * static_cast(endTime)); - loop.comment = toUnicode((*cueExtendedEntry)->comment()); - loop.color = colorFromID(static_cast((*cueExtendedEntry)->color_id())); + loop.comment = toUnicode(cueExtendedEntry->comment()); + loop.color = colorFromID(static_cast(cueExtendedEntry->color_id())); memoryCuesAndLoops << loop; } break; } } break; case rekordbox_anlz_t::CUE_LIST_TYPE_HOT_CUES: { - int hotCueIndex = static_cast((*cueExtendedEntry)->hot_cue() - 1); + int hotCueIndex = static_cast(cueExtendedEntry->hot_cue() - 1); if (hotCueIndex > lastHotCueIndex) { lastHotCueIndex = hotCueIndex; } @@ -1068,13 +1031,13 @@ void readAnalyze(TrackPointer track, position, mixxx::audio::kInvalidFramePos, hotCueIndex, - toUnicode((*cueExtendedEntry)->comment()), + toUnicode(cueExtendedEntry->comment()), mixxx::RgbColor(qRgb( static_cast( - (*cueExtendedEntry)->color_red()), + cueExtendedEntry->color_red()), static_cast( - (*cueExtendedEntry)->color_green()), - static_cast((*cueExtendedEntry) + cueExtendedEntry->color_green()), + static_cast(cueExtendedEntry ->color_blue())))); } break; }