diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nsid3v2/frameheader.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/nsid3v2/frameheader.cpp')
-rw-r--r-- | Src/replicant/nsid3v2/frameheader.cpp | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/Src/replicant/nsid3v2/frameheader.cpp b/Src/replicant/nsid3v2/frameheader.cpp new file mode 100644 index 00000000..3ffa63f9 --- /dev/null +++ b/Src/replicant/nsid3v2/frameheader.cpp @@ -0,0 +1,403 @@ +#include "frameheader.h" +#include "util.h" +#include "values.h" +#include "nu/ByteReader.h" +#include "nu/ByteWriter.h" +#include <string.h> +#include "foundation/error.h" +/* === ID3v2 common === */ +ID3v2::FrameHeader::FrameHeader(const ID3v2::Header &_header) : tagHeader(_header) +{ +} + +static bool CharOK(int8_t c) +{ + if (c >= '0' && c <= '9') + return true; + + if (c >= 'A' && c <= 'Z') + return true; + + return false; +} + +/* === ID3v2.2 === */ +ID3v2_2::FrameHeader::FrameHeader(const ID3v2_2::FrameHeader &frame_header, const ID3v2::Header &_header) : ID3v2::FrameHeader(_header) +{ + frameHeaderData = frame_header.frameHeaderData; +} + +ID3v2_2::FrameHeader::FrameHeader(const ID3v2::Header &_header, const int8_t *id, int flags) : ID3v2::FrameHeader(_header) +{ + memcpy(&frameHeaderData.id, id, 3); + frameHeaderData.id[3]=0; + memset(&frameHeaderData.size, 0, 3); +} + +ID3v2_2::FrameHeader::FrameHeader(const ID3v2::Header &_header, const void *data) : ID3v2::FrameHeader(_header) +{ + char temp_data[FrameHeader::SIZE]; + if (tagHeader.Unsynchronised()) + { + ID3v2::Util::UnsynchroniseTo(temp_data, data, sizeof(temp_data)); + data = temp_data; + } + + bytereader_value_t byte_reader; + bytereader_init(&byte_reader, data, FrameHeader::SIZE); + + bytereader_read_n(&byte_reader, &frameHeaderData.id, 3); + frameHeaderData.id[3]=0; + bytereader_read_n(&byte_reader, &frameHeaderData.size, 3); +} + +bool ID3v2_2::FrameHeader::IsValid() const +{ + if (CharOK(frameHeaderData.id[0]) + && CharOK(frameHeaderData.id[1]) + && CharOK(frameHeaderData.id[2])) + return true; + + return false; +} + +const int8_t *ID3v2_2::FrameHeader::GetIdentifier() const +{ + return frameHeaderData.id; +} + +bool ID3v2_2::FrameHeader::Unsynchronised() const +{ + return tagHeader.Unsynchronised(); +} + +uint32_t ID3v2_2::FrameHeader::FrameSize() const +{ + return (frameHeaderData.size[0] << 16) | (frameHeaderData.size[1] << 8) | (frameHeaderData.size[2]); +} + +void ID3v2_2::FrameHeader::SetSize(uint32_t data_size) +{ + frameHeaderData.size[0] = data_size >> 16; + frameHeaderData.size[1] = data_size >> 8; + frameHeaderData.size[2] = data_size; +} + +int ID3v2_2::FrameHeader::SerializedSize(uint32_t *written) const +{ + if (tagHeader.Unsynchronised()) + { + uint8_t data[SIZE]; + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, data, SIZE); + bytewriter_write_n(&byte_writer, frameHeaderData.id, 3); + bytewriter_write_n(&byte_writer, frameHeaderData.size, 3); + *written = ID3v2::Util::SynchronisedSize(data, SIZE); + } + else + { + *written = SIZE; + } + return NErr_Success; +} + +int ID3v2_2::FrameHeader::Serialize(void *data) const +{ + if (tagHeader.Unsynchronised()) + { + uint8_t temp[SIZE]; + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, temp, SIZE); + bytewriter_write_n(&byte_writer, frameHeaderData.id, 3); + bytewriter_write_n(&byte_writer, frameHeaderData.size, 3); + ID3v2::Util::SynchroniseTo(data, temp, SIZE); + } + else + { + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, data, SIZE); + bytewriter_write_n(&byte_writer, frameHeaderData.id, 3); + bytewriter_write_n(&byte_writer, frameHeaderData.size, 3); + } + return NErr_Success; +} + +/* === ID3v2.3+ common === */ +ID3v2_3::FrameHeaderBase::FrameHeaderBase(const ID3v2_3::FrameHeaderBase &frame_header_base, const ID3v2::Header &_header) : ID3v2::FrameHeader(_header) +{ + memcpy(id, frame_header_base.id, 4); + size=frame_header_base.size; + flags[0] = frame_header_base.flags[0]; + flags[1] = frame_header_base.flags[1]; +} + +ID3v2_3::FrameHeaderBase::FrameHeaderBase(const ID3v2::Header &_header) : ID3v2::FrameHeader(_header) +{ +} + +ID3v2_3::FrameHeaderBase::FrameHeaderBase(const ID3v2::Header &_header, const int8_t *_id, int _flags) : ID3v2::FrameHeader(_header) +{ + memcpy(id, _id, 4); + size=0; + // TODO: flags + flags[0]=0; + flags[1]=0; +} + +const int8_t *ID3v2_3::FrameHeaderBase::GetIdentifier() const +{ + return id; +} + + +bool ID3v2_3::FrameHeaderBase::IsValid() const +{ + if (CharOK(id[0]) + && CharOK(id[1]) + && CharOK(id[2]) + && CharOK(id[3])) + return true; + + return false; +} + + + +/* === ID3v2.3 === */ +ID3v2_3::FrameHeader::FrameHeader(const ID3v2_3::FrameHeader &frame_header, const ID3v2::Header &tag_header) : ID3v2_3::FrameHeaderBase(frame_header, tag_header) +{ +} + +ID3v2_3::FrameHeader::FrameHeader(const ID3v2::Header &_header, const int8_t *id, int flags) : ID3v2_3::FrameHeaderBase(_header, id, flags) +{ +} + +ID3v2_3::FrameHeader::FrameHeader(const ID3v2::Header &_header, const void *data) : ID3v2_3::FrameHeaderBase(_header) +{ + char temp_data[FrameHeaderBase::SIZE]; + if (tagHeader.Unsynchronised()) + { + ID3v2::Util::UnsynchroniseTo(temp_data, data, sizeof(temp_data)); + data = temp_data; + } + + bytereader_value_t byte_reader; + bytereader_init(&byte_reader, data, FrameHeaderBase::SIZE); + + bytereader_read_n(&byte_reader, &id, 4); + size = bytereader_read_u32_be(&byte_reader); + bytereader_read_n(&byte_reader, &flags, 2); +} + +int ID3v2_3::FrameHeaderBase::SerializedSize(uint32_t *written) const +{ + if (tagHeader.Unsynchronised()) + { + uint8_t data[SIZE]; + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, data, SIZE); + bytewriter_write_n(&byte_writer, id, 4); + bytewriter_write_u32_be(&byte_writer, size); + bytewriter_write_u8(&byte_writer, flags[0]); + bytewriter_write_u8(&byte_writer, flags[1]); + *written = ID3v2::Util::SynchronisedSize(data, SIZE); + } + else + { + *written = SIZE; + } + return NErr_Success; +} + +int ID3v2_3::FrameHeaderBase::Serialize(void *data, uint32_t *written) const +{ + if (tagHeader.Unsynchronised()) + { + uint8_t temp[SIZE]; + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, temp, SIZE); + bytewriter_write_n(&byte_writer, id, 4); + bytewriter_write_u32_be(&byte_writer, size); + bytewriter_write_u8(&byte_writer, flags[0]); + bytewriter_write_u8(&byte_writer, flags[1]); + *written = ID3v2::Util::SynchroniseTo(data, temp, SIZE); + } + else + { + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, data, SIZE); + bytewriter_write_n(&byte_writer, id, 4); + bytewriter_write_u32_be(&byte_writer, size); + bytewriter_write_u8(&byte_writer, flags[0]); + bytewriter_write_u8(&byte_writer, flags[1]); + *written = SIZE; + } + return NErr_Success; +} + +uint32_t ID3v2_3::FrameHeader::FrameSize() const +{ + return size; +} + +bool ID3v2_3::FrameHeader::ReadOnly() const +{ + return !!(flags[0] & (1<<5)); +} + +bool ID3v2_3::FrameHeader::Encrypted() const +{ + return !!(flags[1] & (1<<6)); +} + +bool ID3v2_3::FrameHeader::Unsynchronised() const +{ + return tagHeader.Unsynchronised(); +} + +bool ID3v2_3::FrameHeader::Grouped() const +{ + return !!(flags[1] & (1 << 5)); +} + +bool ID3v2_3::FrameHeader::Compressed() const +{ + return !!(flags[1] & (1 << 7)); +} + +bool ID3v2_3::FrameHeader::TagAlterPreservation() const +{ + return !!(flags[0] & (1<<7)); +} + +bool ID3v2_3::FrameHeader::FileAlterPreservation() const +{ + return !!(flags[0] & (1<<6)); +} + +void ID3v2_3::FrameHeader::ClearCompressed() +{ + flags[1] &= ~(1 << 7); +} + +void ID3v2_3::FrameHeader::SetSize(uint32_t data_size) +{ + if (Compressed()) + data_size+=4; + if (Grouped()) + data_size++; + size = data_size; +} + +/* === ID3v2.4 === */ +ID3v2_4::FrameHeader::FrameHeader(const ID3v2_4::FrameHeader &frame_header, const ID3v2::Header &tag_header) : ID3v2_3::FrameHeaderBase(frame_header, tag_header) +{ +} + +ID3v2_4::FrameHeader::FrameHeader(const ID3v2::Header &_header, const int8_t *id, int flags) : ID3v2_3::FrameHeaderBase(_header, id, flags) +{ +} + +ID3v2_4::FrameHeader::FrameHeader(const ID3v2::Header &_header, const void *data) : ID3v2_3::FrameHeaderBase(_header) +{ + bytereader_value_t byte_reader; + bytereader_init(&byte_reader, data, FrameHeaderBase::SIZE); + + bytereader_read_n(&byte_reader, &id, 4); + size = bytereader_read_u32_be(&byte_reader); + bytereader_read_n(&byte_reader, &flags, 2); +} + +uint32_t ID3v2_4::FrameHeader::FrameSize() const +{ + // many programs write non-syncsafe sizes (iTunes is the biggest culprit) + // so we'll try to detect it. unfortunately this isn't foolproof + // ID3v2_4::Frame will have some additional checks + int mask = size & 0x80808080; + if (mask) + return size; + else + return ID3v2::Util::Int28To32(size); +} + +bool ID3v2_4::FrameHeader::ReadOnly() const +{ + return !!(flags[0] & (1<<4)); +} + +bool ID3v2_4::FrameHeader::Encrypted() const +{ + return !!(flags[1] & (1<<3)); +} + +bool ID3v2_4::FrameHeader::Unsynchronised() const +{ + return tagHeader.Unsynchronised() || !!(flags[1] & (1 << 1)); +} + +bool ID3v2_4::FrameHeader::FrameUnsynchronised() const +{ + return !!(flags[1] & (1 << 1)); +} + +bool ID3v2_4::FrameHeader::DataLengthIndicated() const +{ + return !!(flags[1] & (1 << 0)); +} + +bool ID3v2_4::FrameHeader::Compressed() const +{ + return !!(flags[1] & (1 << 3)); +} + +bool ID3v2_4::FrameHeader::Grouped() const +{ + return !!(flags[1] & (1 << 6)); +} + +bool ID3v2_4::FrameHeader::TagAlterPreservation() const +{ + return !!(flags[0] & (1<<6)); +} + +bool ID3v2_4::FrameHeader::FileAlterPreservation() const +{ + return !!(flags[0] & (1<<5)); +} + +void ID3v2_4::FrameHeader::ClearUnsynchronized() +{ + flags[1] &= ~(1 << 1); +} + +void ID3v2_4::FrameHeader::ClearCompressed() +{ + flags[1] &= ~(1 << 3); +} + +void ID3v2_4::FrameHeader::SetSize(uint32_t data_size) +{ + if (Compressed() || DataLengthIndicated()) + data_size+=4; + if (Grouped()) + data_size++; + size = ID3v2::Util::Int32To28(data_size); +} + +int ID3v2_4::FrameHeader::SerializedSize(uint32_t *written) const +{ + *written = SIZE; + return NErr_Success; +} + +int ID3v2_4::FrameHeader::Serialize(void *data, uint32_t *written) const +{ + bytewriter_s byte_writer; + bytewriter_init(&byte_writer, data, SIZE); + bytewriter_write_n(&byte_writer, id, 4); + bytewriter_write_u32_be(&byte_writer, size); + bytewriter_write_u8(&byte_writer, flags[0]); + bytewriter_write_u8(&byte_writer, flags[1]); + *written = SIZE; + return NErr_Success; +} |