From 619ef906cd5af7a37684823532e0b3ae78f68f33 Mon Sep 17 00:00:00 2001 From: Scott Wheeler Date: Fri, 20 Feb 2004 01:41:25 +0000 Subject: [PATCH] Mostly get ID3v2.2 working. Sure, it's a standard from 1998 that was replaced in 1999, but apparently iTunes still uses it. This gets the frame parsing code to support 2.2 and required deprecating a couple of methods so that an ID3v2 version could be passed along. There still needs to be a translation table added to handle converting ID3v2.2 frame names to their ID3v2.4 equivalents, but that can come later. For now the framelister program from the examples dir is able to read all of the text frames. CCMAIL:Keith Brady git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@289567 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- examples/strip-id3v1.cpp | 2 +- mpeg/id3v2/frames/commentsframe.cpp | 8 +- mpeg/id3v2/frames/textidentificationframe.cpp | 2 +- mpeg/id3v2/id3v2frame.cpp | 126 ++++++++++++++---- mpeg/id3v2/id3v2frame.h | 61 ++++++++- mpeg/id3v2/id3v2framefactory.cpp | 11 +- mpeg/id3v2/id3v2framefactory.h | 14 +- mpeg/id3v2/id3v2header.cpp | 4 +- mpeg/id3v2/id3v2tag.cpp | 8 +- 9 files changed, 188 insertions(+), 48 deletions(-) diff --git a/examples/strip-id3v1.cpp b/examples/strip-id3v1.cpp index ab36d711..f8c88916 100644 --- a/examples/strip-id3v1.cpp +++ b/examples/strip-id3v1.cpp @@ -35,6 +35,6 @@ int main(int argc, char *argv[]) std::cout << "******************** Stripping ID3v1 Tag From: \"" << argv[i] << "\"********************" << std::endl; MPEG::File f(argv[i]); - f.strip(MPEG::File::ID3v1); + f.strip(); } } diff --git a/mpeg/id3v2/frames/commentsframe.cpp b/mpeg/id3v2/frames/commentsframe.cpp index 4a9083f6..99af7a4a 100644 --- a/mpeg/id3v2/frames/commentsframe.cpp +++ b/mpeg/id3v2/frames/commentsframe.cpp @@ -43,14 +43,14 @@ public: CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM") { - d = new CommentsFramePrivate(); + d = new CommentsFramePrivate; d->textEncoding = encoding; } CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data) { - d = new CommentsFramePrivate(); - parseFields(data.mid(Header::size(), size())); + d = new CommentsFramePrivate; + parseFields(data.mid(Header::size(header()->version()), size())); } CommentsFrame::~CommentsFrame() @@ -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(), size())); + parseFields(data.mid(Header::size(h->version()), size())); } diff --git a/mpeg/id3v2/frames/textidentificationframe.cpp b/mpeg/id3v2/frames/textidentificationframe.cpp index ae76fb9c..0d696861 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(), size())); + parseFields(data.mid(Header::size(h->version()), size())); } diff --git a/mpeg/id3v2/id3v2frame.cpp b/mpeg/id3v2/id3v2frame.cpp index 5f0f894a..2180e6ef 100644 --- a/mpeg/id3v2/id3v2frame.cpp +++ b/mpeg/id3v2/id3v2frame.cpp @@ -50,6 +50,11 @@ TagLib::uint Frame::headerSize() return Header::size(); } +TagLib::uint Frame::headerSize(uint version) +{ + return Header::size(version); +} + ByteVector Frame::textDelimiter(String::Type t) { ByteVector d = char(0); @@ -108,13 +113,13 @@ ByteVector Frame::render() const Frame::Frame(const ByteVector &data) { - d = new FramePrivate(); + d = new FramePrivate; d->header = new Header(data); } Frame::Frame(Header *h) { - d = new FramePrivate(); + d = new FramePrivate; d->header = h; } @@ -139,7 +144,8 @@ void Frame::parse(const ByteVector &data) d->header = new Header(data); // size() is the lenght of the field data - parseFields(data.mid(Header::size(), size())); + + parseFields(data.mid(Header::size(d->header->version()), size())); } //////////////////////////////////////////////////////////////////////////////// @@ -149,11 +155,11 @@ void Frame::parse(const ByteVector &data) class Frame::Header::HeaderPrivate { public: - HeaderPrivate() : frameSize(0) {} + HeaderPrivate() : frameSize(0), version(4) {} ByteVector frameID; uint frameSize; - static const unsigned int size = 10; + uint version; }; //////////////////////////////////////////////////////////////////////////////// @@ -162,7 +168,21 @@ public: TagLib::uint Frame::Header::size() { - return HeaderPrivate::size; + return size(4); +} + +TagLib::uint Frame::Header::size(uint version) +{ + switch(version) { + case 0: + case 1: + case 2: + return 6; + case 3: + case 4: + default: + return 10; + } } //////////////////////////////////////////////////////////////////////////////// @@ -175,6 +195,12 @@ Frame::Header::Header(const ByteVector &data, bool synchSafeInts) setData(data, synchSafeInts); } +Frame::Header::Header(const ByteVector &data, uint version) +{ + d = new HeaderPrivate; + setData(data, version); +} + Frame::Header::~Header() { delete d; @@ -182,33 +208,78 @@ Frame::Header::~Header() void Frame::Header::setData(const ByteVector &data, bool synchSafeInts) { - if(data.size() < 4) { - debug("You must at least specify a frame ID."); - return; - } + setData(data, uint(synchSafeInts ? 4 : 3)); +} + +void Frame::Header::setData(const ByteVector &data, uint version) +{ + d->version = version; + + switch(version) { + case 0: + case 1: + case 2: + { - // set the frame ID -- the first four bytes + // ID3v2.2 - d->frameID = data.mid(0, 4); + if(data.size() < 3) { + debug("You must at least specify a frame ID."); + return; + } - // If the full header information was not passed in, do not continue to the - // steps to parse the frame size and flags. + // Set the frame ID -- the first three bytes - if(data.size() < 10) { - d->frameSize = 0; - return; + d->frameID = data.mid(0, 3); + + // If the full header information was not passed in, do not continue to the + // steps to parse the frame size and flags. + + if(data.size() < 6) { + d->frameSize = 0; + return; + } + + d->frameSize = data.mid(3, 3).toUInt(); + + break; } + case 3: + case 4: + default: + { + // ID3v2.3 / ID3v2.4 - // Set the size -- the frame size is the four bytes starting at byte four in - // the frame header (structure 4) + if(data.size() < 4) { + debug("You must at least specify a frame ID."); + return; + } - if(synchSafeInts) - d->frameSize = SynchData::toUInt(data.mid(4, 4)); - else - d->frameSize = data.mid(4, 4).toUInt(); + // Set the frame ID -- the first four bytes + + d->frameID = data.mid(0, 4); + + // If the full header information was not passed in, do not continue to the + // steps to parse the frame size and flags. + + if(data.size() < 10) { + d->frameSize = 0; + return; + } - // read flags - // ... + // Set the size -- the frame size is the four bytes starting at byte four in + // the frame header (structure 4) + + if(version >= 4) + d->frameSize = SynchData::toUInt(data.mid(4, 4)); + else + d->frameSize = data.mid(4, 4).toUInt(); + + // TODO: read flags + + break; + } + } } ByteVector Frame::Header::frameID() const @@ -231,6 +302,11 @@ void Frame::Header::setFrameSize(uint size) d->frameSize = size; } +TagLib::uint Frame::Header::version() const +{ + return d->version; +} + 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 b772ea40..920429c6 100644 --- a/mpeg/id3v2/id3v2frame.h +++ b/mpeg/id3v2/id3v2frame.h @@ -65,8 +65,20 @@ namespace TagLib { /*! * Returns the size of the frame header + * + * \deprecated This is only accurate for ID3v2.3 or ID3v2.4. Please use + * the call below which accepts an ID3v2 version number. In the next + * non-binary compatible release this will be made into a non-static + * member that checks the internal ID3v2 version. */ - static uint headerSize(); + static uint headerSize(); // BIC: remove and make non-static + + /*! + * Returns the size of the frame header for the given ID3v2 version. + * + * \deprecated Please see the explanation above. + */ + static uint headerSize(uint version); // BIC: remove and make non-static /*! * Sets the data that will be used as the frame. Since the length is not @@ -187,8 +199,20 @@ namespace TagLib { * Construct a Frame Header based on \a data. \a data must at least * contain a 4 byte frame ID, and optionally can contain flag data and the * frame size. i.e. Just the frame id -- "TALB" -- is a valid value. + * + * \deprecated Please use the constructor below that accepts a version + * number. + */ + explicit Header(const ByteVector &data, bool synchSafeInts); + + /*! + * Construct a Frame Header based on \a data. \a data must at least + * contain a 4 byte frame ID, and optionally can contain flag data and the + * frame size. i.e. Just the frame id -- "TALB" -- is a valid value. + * + * \a version should be the ID3v2 version of the tag. */ - explicit Header(const ByteVector &data, bool synchSafeInts = true); + explicit Header(const ByteVector &data, uint version = 4); /*! * Destroys this Header instance. @@ -197,8 +221,17 @@ namespace TagLib { /*! * Sets the data for the Header. + * + * \deprecated Please use the version below that accepts an ID3v2 version + * number. + */ + void setData(const ByteVector &data, bool synchSafeInts); + + /*! + * Sets the data for the Header. \a version should indicate the ID3v2 + * version number of the tag that this frame is contained in. */ - void setData(const ByteVector &data, bool synchSafeInts = true); + void setData(const ByteVector &data, uint version = 4); /*! * Returns the Frame ID (Structure, 4) @@ -228,11 +261,29 @@ namespace TagLib { void setFrameSize(uint size); /*! - * Returns the size of the frame header in bytes. Currently this is - * always 10. + * Returns the ID3v2 version of the header (as passed in from the + * construction of the header). + */ + uint version() const; + + /*! + * Returns the size of the frame header in bytes. + * + * \deprecated Please use the version of this method that accepts a + * version. This is only accurate for ID3v2.3 and ID3v2.4. This will be + * removed in the next binary incompatible release (2.0) and will be + * replaced with a non-static method that checks the frame version. */ static uint size(); + /*! + * Returns the size of the frame header in bytes for the ID3v2 version + * that's given. + * + * \deprecated Please see the explanation in the version above. + */ + static uint size(uint version); + /*! * Render the Header back to binary format in a ByteVector. */ diff --git a/mpeg/id3v2/id3v2framefactory.cpp b/mpeg/id3v2/id3v2framefactory.cpp index 8d4352fa..aa9189ae 100644 --- a/mpeg/id3v2/id3v2framefactory.cpp +++ b/mpeg/id3v2/id3v2framefactory.cpp @@ -56,15 +56,20 @@ FrameFactory *FrameFactory::instance() Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const { - Frame::Header *header = new Frame::Header(data, synchSafeInts); + return createFrame(data, uint(synchSafeInts ? 4 : 3)); +} + +Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const +{ + Frame::Header *header = new Frame::Header(data, version); TagLib::ByteVector frameID = header->frameID(); // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1 // characters. Also make sure that there is data in the frame. - if(!frameID.size() == 4 || header->frameSize() <= 0) - return 0; + if(!frameID.size() == (version < 3 ? 3 : 4) || header->frameSize() <= 0) + return 0; for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) { diff --git a/mpeg/id3v2/id3v2framefactory.h b/mpeg/id3v2/id3v2framefactory.h index f1cefcde..544b0f0e 100644 --- a/mpeg/id3v2/id3v2framefactory.h +++ b/mpeg/id3v2/id3v2framefactory.h @@ -1,4 +1,4 @@ -/*************************************************************************** + /*************************************************************************** copyright : (C) 2002, 2003 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ @@ -56,8 +56,18 @@ namespace TagLib { * Create a frame based on \a data. \a synchSafeInts should only be set * false if we are parsing an old tag (v2.3 or older) that does not support * synchsafe ints. + * + * \deprecated Please use the method below that accepts an ID3 version + * number in new code. + */ + Frame *createFrame(const ByteVector &data, bool synchSafeInts) const; + + /*! + * Create a frame based on \a data. \a version should indicate the ID3v2 + * version of the tag. As ID3v2.4 is the most current version of the + * standard 4 is the default. */ - Frame *createFrame(const ByteVector &data, bool synchSafeInts = true) const; + Frame *createFrame(const ByteVector &data, uint version = 4) const; /*! * Returns the default text encoding for text frames. If setTextEncoding() diff --git a/mpeg/id3v2/id3v2header.cpp b/mpeg/id3v2/id3v2header.cpp index caa28e2c..4ed09e8a 100644 --- a/mpeg/id3v2/id3v2header.cpp +++ b/mpeg/id3v2/id3v2header.cpp @@ -78,12 +78,12 @@ ByteVector Header::fileIdentifier() Header::Header() { - d = new HeaderPrivate(); + d = new HeaderPrivate; } Header::Header(const ByteVector &data) { - d = new HeaderPrivate(); + d = new HeaderPrivate; parse(data); } diff --git a/mpeg/id3v2/id3v2tag.cpp b/mpeg/id3v2/id3v2tag.cpp index 871cd130..a3a0d60e 100644 --- a/mpeg/id3v2/id3v2tag.cpp +++ b/mpeg/id3v2/id3v2tag.cpp @@ -365,7 +365,7 @@ void ID3v2::Tag::parse(const ByteVector &data) // Make sure that there is at least enough room in the remaining frame data for // a frame header. - while(frameDataPosition < frameDataLength - Frame::headerSize()) { + while(frameDataPosition < frameDataLength - Frame::headerSize(d->header.majorVersion())) { // If the next data is position is 0, assume that we've hit the padding // portion of the frame data. @@ -379,10 +379,8 @@ void ID3v2::Tag::parse(const ByteVector &data) return; } - bool synchSafeInts = d->header.majorVersion() >= 4; - Frame *frame = d->factory->createFrame(data.mid(frameDataOffset + frameDataPosition), - synchSafeInts); + d->header.majorVersion()); if(!frame) return; @@ -394,7 +392,7 @@ void ID3v2::Tag::parse(const ByteVector &data) return; } - frameDataPosition += frame->size() + Frame::headerSize(); + frameDataPosition += frame->size() + Frame::headerSize(d->header.majorVersion()); addFrame(frame); } } -- 2.50.1