diff --git a/mpeg/id3v2/frames/attachedpictureframe.cpp b/mpeg/id3v2/frames/attachedpictureframe.cpp index 35a6a7ef..5700dfe6 100644 --- a/mpeg/id3v2/frames/attachedpictureframe.cpp +++ b/mpeg/id3v2/frames/attachedpictureframe.cpp @@ -161,5 +161,5 @@ ByteVector AttachedPictureFrame::renderFields() const AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h) { d = new AttachedPictureFramePrivate; - parseFields(data.mid(Header::size(h->version()), size())); + parseFields(fieldData(data)); } diff --git a/mpeg/id3v2/frames/commentsframe.cpp b/mpeg/id3v2/frames/commentsframe.cpp index 99af7a4a..066fed07 100644 --- a/mpeg/id3v2/frames/commentsframe.cpp +++ b/mpeg/id3v2/frames/commentsframe.cpp @@ -148,5 +148,5 @@ ByteVector CommentsFrame::renderFields() const CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h) { d = new CommentsFramePrivate(); - parseFields(data.mid(Header::size(h->version()), size())); + parseFields(fieldData(data)); } diff --git a/mpeg/id3v2/frames/relativevolumeframe.cpp b/mpeg/id3v2/frames/relativevolumeframe.cpp index acbd689a..171ba91d 100644 --- a/mpeg/id3v2/frames/relativevolumeframe.cpp +++ b/mpeg/id3v2/frames/relativevolumeframe.cpp @@ -133,5 +133,5 @@ ByteVector RelativeVolumeFrame::renderFields() const RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h) { d = new RelativeVolumeFramePrivate; - parseFields(data.mid(Header::size(h->version()), size())); + parseFields(fieldData(data)); } diff --git a/mpeg/id3v2/frames/textidentificationframe.cpp b/mpeg/id3v2/frames/textidentificationframe.cpp index 3d158297..90e06e5f 100644 --- a/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/mpeg/id3v2/frames/textidentificationframe.cpp @@ -146,5 +146,5 @@ ByteVector TextIdentificationFrame::renderFields() const TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h) { d = new TextIdentificationFramePrivate; - parseFields(data.mid(Header::size(h->version()), size())); + parseFields(fieldData(data)); } diff --git a/mpeg/id3v2/frames/unknownframe.cpp b/mpeg/id3v2/frames/unknownframe.cpp index 96723e3e..0f4ed2e8 100644 --- a/mpeg/id3v2/frames/unknownframe.cpp +++ b/mpeg/id3v2/frames/unknownframe.cpp @@ -76,5 +76,5 @@ ByteVector UnknownFrame::renderFields() const UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h) { d = new UnknownFramePrivate; - parseFields(data.mid(Header::size(h->version()), size())); + parseFields(fieldData(data)); } diff --git a/mpeg/id3v2/id3v2frame.cpp b/mpeg/id3v2/id3v2frame.cpp index 2180e6ef..8b7c1192 100644 --- a/mpeg/id3v2/id3v2frame.cpp +++ b/mpeg/id3v2/id3v2frame.cpp @@ -19,6 +19,8 @@ * USA * ***************************************************************************/ +#include + #include #include "id3v2frame.h" @@ -30,11 +32,12 @@ using namespace ID3v2; class Frame::FramePrivate { public: - FramePrivate() { - header = 0; - } + FramePrivate() : + header(0) + {} - ~FramePrivate() { + ~FramePrivate() + { delete header; } @@ -143,9 +146,22 @@ void Frame::parse(const ByteVector &data) else d->header = new Header(data); - // size() is the lenght of the field data + parseFields(fieldData(data)); +} - parseFields(data.mid(Header::size(d->header->version()), size())); +ByteVector Frame::fieldData(const ByteVector &frameData) const +{ + uint headerSize = Header::size(d->header->version()); + + uint frameDataOffset = headerSize; + uint frameDataLength = size(); + + if(d->header->dataLengthIndicator()) { + frameDataLength = frameData.mid(headerSize, 4).toUInt(); + frameDataOffset += 4; + } + + return frameData.mid(frameDataOffset, frameDataLength); } //////////////////////////////////////////////////////////////////////////////// @@ -155,11 +171,33 @@ void Frame::parse(const ByteVector &data) class Frame::Header::HeaderPrivate { public: - HeaderPrivate() : frameSize(0), version(4) {} + HeaderPrivate() : + frameSize(0), + version(4), + tagAlterPreservation(false), + frameAlterPreservation(false), + readOnly(false), + groupingIdentity(false), + compression(false), + encryption(false), + unsyncronisation(false), + dataLengthIndicator(false) + {} ByteVector frameID; uint frameSize; uint version; + + // flags + + bool tagAlterPreservation; + bool frameAlterPreservation; + bool readOnly; + bool groupingIdentity; + bool compression; + bool encryption; + bool unsyncronisation; + bool dataLengthIndicator; }; //////////////////////////////////////////////////////////////////////////////// @@ -213,7 +251,7 @@ void Frame::Header::setData(const ByteVector &data, bool synchSafeInts) void Frame::Header::setData(const ByteVector &data, uint version) { - d->version = version; + d->version = version; switch(version) { case 0: @@ -275,8 +313,21 @@ void Frame::Header::setData(const ByteVector &data, uint version) else d->frameSize = data.mid(4, 4).toUInt(); - // TODO: read flags + { // read the first byte of flags + std::bitset<8> flags(data[8]); + d->tagAlterPreservation = flags[6]; // (structure 4.1.1.a) + d->frameAlterPreservation = flags[5]; // (structure 4.1.1.b) + d->readOnly = flags[4]; // (structure 4.1.1.c) + } + { // read the second byte of flags + std::bitset<8> flags(data[9]); + d->groupingIdentity = flags[6]; // (structure 4.1.2.h) + d->compression = flags[3]; // (structure 4.1.2.k) + d->encryption = flags[2]; // (structure 4.1.2.m) + d->unsyncronisation = flags[1]; // (structure 4.1.2.n) + d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p) + } break; } } @@ -307,6 +358,46 @@ TagLib::uint Frame::Header::version() const return d->version; } +bool Frame::Header::tagAlterPreservation() const +{ + return d->tagAlterPreservation; +} + +bool Frame::Header::frameAlterPreservation() const +{ + return d->frameAlterPreservation; +} + +bool Frame::Header::readOnly() const +{ + return d->readOnly; +} + +bool Frame::Header::groupingIdentity() const +{ + return d->groupingIdentity; +} + +bool Frame::Header::compression() const +{ + return d->compression; +} + +bool Frame::Header::encryption() const +{ + return d->encryption; +} + +bool Frame::Header::unsycronisation() const +{ + return d->unsyncronisation; +} + +bool Frame::Header::dataLengthIndicator() const +{ + return d->dataLengthIndicator; +} + ByteVector Frame::Header::render() const { ByteVector flags(2, char(0)); // just blank for the moment diff --git a/mpeg/id3v2/id3v2frame.h b/mpeg/id3v2/id3v2frame.h index b78fa300..cdcc76d5 100644 --- a/mpeg/id3v2/id3v2frame.h +++ b/mpeg/id3v2/id3v2frame.h @@ -170,6 +170,13 @@ namespace TagLib { */ virtual ByteVector renderFields() const = 0; + /*! + * Returns a ByteVector containing the field data given the frame data. + * This correctly adjusts for the header size plus any additional frame + * data that's specified in the frame header flags. + */ + ByteVector fieldData(const ByteVector &frameData) const; + private: Frame(const Frame &); Frame &operator=(const Frame &); @@ -284,6 +291,60 @@ namespace TagLib { */ static uint size(uint version); + /*! + * Returns true if the flag for tag alter preservation is set. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool tagAlterPreservation() const; + + /*! + * Returns true if the flag for frame alter preservation is set. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool frameAlterPreservation() const; + + /*! + * Returns true if the frame is meant to be read only. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool readOnly() const; + + /*! + * Returns true if the flag for the grouping identifity is set. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool groupingIdentity() const; + + /*! + * Returns true if compression is enabled for this frame. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool compression() const; + + /*! + * Returns true if encryption is enabled for this frame. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool encryption() const; + + /*! + * Returns true if unsyncronisation is enabled for this frame. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool unsycronisation() const; + + /*! + * Returns true if the flag for a data lenght indicator is set. + */ + bool dataLengthIndicator() const; + /*! * Render the Header back to binary format in a ByteVector. */ diff --git a/mpeg/id3v2/id3v2tag.cpp b/mpeg/id3v2/id3v2tag.cpp index c629bdd9..046db563 100644 --- a/mpeg/id3v2/id3v2tag.cpp +++ b/mpeg/id3v2/id3v2tag.cpp @@ -386,7 +386,7 @@ void ID3v2::Tag::read() void ID3v2::Tag::parse(const ByteVector &data) { - uint frameDataOffset = 0; + uint frameDataPosition = 0; uint frameDataLength = data.size(); // check for extended header @@ -396,7 +396,7 @@ void ID3v2::Tag::parse(const ByteVector &data) d->extendedHeader = new ExtendedHeader; d->extendedHeader->setData(data); if(d->extendedHeader->size() <= data.size()) { - frameDataOffset += d->extendedHeader->size(); + frameDataPosition += d->extendedHeader->size(); frameDataLength -= d->extendedHeader->size(); } } @@ -410,8 +410,6 @@ void ID3v2::Tag::parse(const ByteVector &data) // parse frames - uint frameDataPosition = 0; - // Make sure that there is at least enough room in the remaining frame data for // a frame header. @@ -421,7 +419,6 @@ void ID3v2::Tag::parse(const ByteVector &data) // portion of the frame data. if(data.at(frameDataPosition) == 0) { - if(d->header.footerPresent()) debug("Padding *and* a footer found. This is not allowed by the spec."); @@ -429,7 +426,7 @@ void ID3v2::Tag::parse(const ByteVector &data) return; } - Frame *frame = d->factory->createFrame(data.mid(frameDataOffset + frameDataPosition), + Frame *frame = d->factory->createFrame(data.mid(frameDataPosition), d->header.majorVersion()); if(!frame)