mirror of
https://github.com/taglib/taglib.git
synced 2025-06-03 17:18:11 -04:00
Fix a number of bugs to get things working with ID3v2.4 tags generated by
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
This commit is contained in:
parent
d8fc67ac67
commit
3a81dfb883
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include <tdebug.h>
|
||||
|
||||
#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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user