libid3tag:
*) Handle the case of there being an extended header where the first byte
is zero (this was running into a check to see if the padding had been
reached)
*) Add support for reading ID3v2::Frame::Header flags. Previously this
was not implemented, but was needed to...
*) Properly adjust the reading position for the existance of a data length
indicator at the beginning of frames
Things now seem to work with the test files that I have here. Since this
is the only other ID3v2.4 implmentation that I know of "in the wild" it's
nice that they now play nice together. libid3tag uses many more of the
unique ID3v2.4 features than TagLib does.
CCMAIL:82867-done@bugs.kde.org
git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@332778
283d02a7-25f6-0310-bc7c-
ecb5cbfe19da
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new AttachedPictureFramePrivate;
- parseFields(data.mid(Header::size(h->version()), size()));
+ parseFields(fieldData(data));
}
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new CommentsFramePrivate();
- parseFields(data.mid(Header::size(h->version()), size()));
+ parseFields(fieldData(data));
}
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new RelativeVolumeFramePrivate;
- parseFields(data.mid(Header::size(h->version()), size()));
+ parseFields(fieldData(data));
}
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new TextIdentificationFramePrivate;
- parseFields(data.mid(Header::size(h->version()), size()));
+ parseFields(fieldData(data));
}
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new UnknownFramePrivate;
- parseFields(data.mid(Header::size(h->version()), size()));
+ parseFields(fieldData(data));
}
* USA *
***************************************************************************/
+#include <bitset>
+
#include <tdebug.h>
#include "id3v2frame.h"
class Frame::FramePrivate
{
public:
- FramePrivate() {
- header = 0;
- }
+ FramePrivate() :
+ header(0)
+ {}
- ~FramePrivate() {
+ ~FramePrivate()
+ {
delete header;
}
else
d->header = new Header(data);
- // size() is the lenght of the field data
+ parseFields(fieldData(data));
+}
+
+ByteVector Frame::fieldData(const ByteVector &frameData) const
+{
+ uint headerSize = Header::size(d->header->version());
+
+ uint frameDataOffset = headerSize;
+ uint frameDataLength = size();
- parseFields(data.mid(Header::size(d->header->version()), size()));
+ if(d->header->dataLengthIndicator()) {
+ frameDataLength = frameData.mid(headerSize, 4).toUInt();
+ frameDataOffset += 4;
+ }
+
+ return frameData.mid(frameDataOffset, frameDataLength);
}
////////////////////////////////////////////////////////////////////////////////
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;
};
////////////////////////////////////////////////////////////////////////////////
void Frame::Header::setData(const ByteVector &data, uint version)
{
- d->version = version;
+ d->version = version;
switch(version) {
case 0:
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;
}
}
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
*/
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 &);
*/
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.
*/
void ID3v2::Tag::parse(const ByteVector &data)
{
- uint frameDataOffset = 0;
+ uint frameDataPosition = 0;
uint frameDataLength = data.size();
// check for extended header
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();
}
}
// parse frames
- uint frameDataPosition = 0;
-
// Make sure that there is at least enough room in the remaining frame data for
// a frame header.
// 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.");
return;
}
- Frame *frame = d->factory->createFrame(data.mid(frameDataOffset + frameDataPosition),
+ Frame *frame = d->factory->createFrame(data.mid(frameDataPosition),
d->header.majorVersion());
if(!frame)