From e06495a7e3e26acc6f497000ad23020d8faadb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Thu, 22 Nov 2007 13:48:01 +0000 Subject: [PATCH] Support for URL link framesSupport for URL link frames, patch by Urs Fleisch. BUG:151079 CCMAIL:ufleisch@users.sourceforge.net git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@740080 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- taglib/CMakeLists.txt | 1 + taglib/mpeg/id3v2/frames/CMakeLists.txt | 45 ++---- taglib/mpeg/id3v2/frames/Makefile.am | 6 +- taglib/mpeg/id3v2/frames/urllinkframe.cpp | 186 ++++++++++++++++++++++ taglib/mpeg/id3v2/frames/urllinkframe.h | 167 +++++++++++++++++++ taglib/mpeg/id3v2/id3v2framefactory.cpp | 14 ++ tests/test_id3v2.cpp | 55 +++++++ 7 files changed, 437 insertions(+), 37 deletions(-) create mode 100644 taglib/mpeg/id3v2/frames/urllinkframe.cpp create mode 100644 taglib/mpeg/id3v2/frames/urllinkframe.h diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index 9957458f..b0361858 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -67,6 +67,7 @@ mpeg/id3v2/frames/relativevolumeframe.cpp mpeg/id3v2/frames/textidentificationframe.cpp mpeg/id3v2/frames/uniquefileidentifierframe.cpp mpeg/id3v2/frames/unknownframe.cpp +mpeg/id3v2/frames/urllinkframe.cpp ) SET(ogg_SRCS diff --git a/taglib/mpeg/id3v2/frames/CMakeLists.txt b/taglib/mpeg/id3v2/frames/CMakeLists.txt index e076918b..90716949 100644 --- a/taglib/mpeg/id3v2/frames/CMakeLists.txt +++ b/taglib/mpeg/id3v2/frames/CMakeLists.txt @@ -1,35 +1,10 @@ -INSTALL( FILES attachedpictureframe.h commentsframe.h generalencapsulatedobjectframe.h relativevolumeframe.h textidentificationframe.h uniquefileidentifierframe.h unknownframe.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib) - - - -#original Makefile.am contents follow: - -#INCLUDES = \ -# -I$(top_srcdir)/taglib \ -# -I$(top_srcdir)/taglib/toolkit \ -# -I$(top_srcdir)/taglib/mpeg/id3v2 \ -# $(all_includes) -# -#noinst_LTLIBRARIES = libframes.la -# -#libframes_la_SOURCES = \ -# attachedpictureframe.cpp \ -# commentsframe.cpp \ -# generalencapsulatedobjectframe.cpp \ -# relativevolumeframe.cpp \ -# textidentificationframe.cpp \ -# uniquefileidentifierframe.cpp \ -# unknownframe.cpp -# -#taglib_include_HEADERS = \ -# attachedpictureframe.h \ -# commentsframe.h \ -# generalencapsulatedobjectframe.h \ -# relativevolumeframe.h \ -# textidentificationframe.h \ -# uniquefileidentifierframe.h \ -# unknownframe.h -# -#taglib_includedir = $(includedir)/taglib -# -#EXTRA_DIST = $(libframes_la_SOURCES) $(taglib_include_HEADERS) +INSTALL(FILES + attachedpictureframe.h + commentsframe.h + generalencapsulatedobjectframe.h + relativevolumeframe.h + textidentificationframe.h + uniquefileidentifierframe.h + unknownframe.h + urllinkframe.h + DESTINATION ${INCLUDE_INSTALL_DIR}/taglib) diff --git a/taglib/mpeg/id3v2/frames/Makefile.am b/taglib/mpeg/id3v2/frames/Makefile.am index 8026a233..bb8affd4 100644 --- a/taglib/mpeg/id3v2/frames/Makefile.am +++ b/taglib/mpeg/id3v2/frames/Makefile.am @@ -13,7 +13,8 @@ libframes_la_SOURCES = \ relativevolumeframe.cpp \ textidentificationframe.cpp \ uniquefileidentifierframe.cpp \ - unknownframe.cpp + unknownframe.cpp \ + urllinkframe.cpp taglib_include_HEADERS = \ attachedpictureframe.h \ @@ -22,6 +23,7 @@ taglib_include_HEADERS = \ relativevolumeframe.h \ textidentificationframe.h \ uniquefileidentifierframe.h \ - unknownframe.h + unknownframe.h \ + urllinkframe.h taglib_includedir = $(includedir)/taglib diff --git a/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/taglib/mpeg/id3v2/frames/urllinkframe.cpp new file mode 100644 index 00000000..2e9ac593 --- /dev/null +++ b/taglib/mpeg/id3v2/frames/urllinkframe.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + copyright : (C) 2006 by Urs Fleisch + email : ufleisch@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#include "urllinkframe.h" +#include + +using namespace TagLib; +using namespace ID3v2; + +class UrlLinkFrame::UrlLinkFramePrivate { +public: + String url; +}; + +class UserUrlLinkFrame::UserUrlLinkFramePrivate { +public: + UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {} + String::Type textEncoding; + String description; +}; + +UrlLinkFrame::UrlLinkFrame(const ByteVector &data) : + Frame(data) +{ + d = new UrlLinkFramePrivate; + setData(data); +} + +UrlLinkFrame::~UrlLinkFrame() +{ + delete d; +} + +void UrlLinkFrame::setUrl(const String &s) +{ + d->url = s; +} + +String UrlLinkFrame::url() const +{ + return d->url; +} + +void UrlLinkFrame::setText(const String &s) +{ + setUrl(s); +} + +String UrlLinkFrame::toString() const +{ + return url(); +} + +void UrlLinkFrame::parseFields(const ByteVector &data) +{ + d->url = String(data); +} + +ByteVector UrlLinkFrame::renderFields() const +{ + return d->url.data(String::Latin1); +} + +UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new UrlLinkFramePrivate; + parseFields(fieldData(data)); +} + + +UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) : + UrlLinkFrame("WXXX") +{ + d = new UserUrlLinkFramePrivate; + d->textEncoding = encoding; +} + +UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) : + UrlLinkFrame(data) +{ + d = new UserUrlLinkFramePrivate; + setData(data); +} + +UserUrlLinkFrame::~UserUrlLinkFrame() +{ + delete d; +} + +String UserUrlLinkFrame::toString() const +{ + return "[" + description() + "] " + url(); +} + +String::Type UserUrlLinkFrame::textEncoding() const +{ + return d->textEncoding; +} + +void UserUrlLinkFrame::setTextEncoding(String::Type encoding) +{ + d->textEncoding = encoding; +} + +String UserUrlLinkFrame::description() const +{ + return d->description; +} + +void UserUrlLinkFrame::setDescription(const String &s) +{ + d->description = s; +} + +void UserUrlLinkFrame::parseFields(const ByteVector &data) +{ + if (data.size() < 2) { + debug("A user URL link frame must contain at least 2 bytes."); + return; + } + + int pos = 0; + + d->textEncoding = String::Type(data[0]); + pos += 1; + + if (d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) { + int offset = data.find(textDelimiter(d->textEncoding), pos); + if (offset < pos) + return; + + d->description = String(data.mid(pos, offset - pos), d->textEncoding); + pos = offset + 1; + } else { + int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2); + if (len < 0) + return; + + d->description = String(data.mid(pos, len), d->textEncoding); + pos += len + 2; + } + + setUrl(String(data.mid(pos))); +} + +ByteVector UserUrlLinkFrame::renderFields() const +{ + ByteVector v; + + v.append(char(d->textEncoding)); + v.append(d->description.data(d->textEncoding)); + v.append(textDelimiter(d->textEncoding)); + v.append(url().data(String::Latin1)); + + return v; +} + +UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h) +{ + d = new UserUrlLinkFramePrivate; + parseFields(fieldData(data)); +} diff --git a/taglib/mpeg/id3v2/frames/urllinkframe.h b/taglib/mpeg/id3v2/frames/urllinkframe.h new file mode 100644 index 00000000..8ff2ec95 --- /dev/null +++ b/taglib/mpeg/id3v2/frames/urllinkframe.h @@ -0,0 +1,167 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + copyright : (C) 2006 by Urs Fleisch + email : ufleisch@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#ifndef TAGLIB_URLLINKFRAME_H +#define TAGLIB_URLLINKFRAME_H + +#include + +namespace TagLib { + + namespace ID3v2 { + + /*! + * An implementation of ID3v2 URL link frames. + */ + class UrlLinkFrame : public Frame { + friend class FrameFactory; + + public: + /*! + * This is a dual purpose constructor. \a data can either be binary data + * that should be parsed or (at a minimum) the frame ID. + */ + explicit UrlLinkFrame(const ByteVector &data); + + /*! + * Destroys this UrlLinkFrame instance. + */ + virtual ~UrlLinkFrame(); + + /*! + * Returns the URL. + */ + virtual String url() const; + + /*! + * Sets the URL to \a s. + */ + virtual void setUrl(const String &s); + + // Reimplementations. + + virtual void setText(const String &s); + virtual String toString() const; + + protected: + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + /*! + * The constructor used by the FrameFactory. + */ + UrlLinkFrame(const ByteVector &data, Header *h); + + private: + UrlLinkFrame(const UrlLinkFrame &); + UrlLinkFrame &operator=(const UrlLinkFrame &); + + class UrlLinkFramePrivate; + UrlLinkFramePrivate *d; + }; + + /*! + * This is a specialization of URL link frames that allows for + * user defined entries. Each entry has a description in addition to the + * normal list of fields that a URL link frame has. + * + * This description identifies the frame and must be unique. + */ + class UserUrlLinkFrame : public UrlLinkFrame { + friend class FrameFactory; + + public: + /*! + * Constructs an empty user defined URL link frame. For this to be + * a useful frame both a description and text must be set. + */ + explicit UserUrlLinkFrame(String::Type encoding = String::Latin1); + + /*! + * This is a dual purpose constructor. \a data can either be binary data + * that should be parsed or (at a minimum) the frame ID. + */ + explicit UserUrlLinkFrame(const ByteVector &data); + + /*! + * Destroys this UserUrlLinkFrame instance. + */ + virtual ~UserUrlLinkFrame(); + + // Reimplementations. + + virtual String toString() const; + + /*! + * Returns the text encoding that will be used in rendering this frame. + * This defaults to the type that was either specified in the constructor + * or read from the frame when parsed. + * + * \see setTextEncoding() + * \see render() + */ + String::Type textEncoding() const; + + /*! + * Sets the text encoding to be used when rendering this frame to + * \a encoding. + * + * \see textEncoding() + * \see render() + */ + void setTextEncoding(String::Type encoding); + + /*! + * Returns the description for this frame. + */ + String description() const; + + /*! + * Sets the description of the frame to \a s. \a s must be unique. + */ + void setDescription(const String &s); + + protected: + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + /*! + * The constructor used by the FrameFactory. + */ + UserUrlLinkFrame(const ByteVector &data, Header *h); + + private: + UserUrlLinkFrame(const UserUrlLinkFrame &); + UserUrlLinkFrame &operator=(const UserUrlLinkFrame &); + + class UserUrlLinkFramePrivate; + UserUrlLinkFramePrivate *d; + }; + + } +} +#endif diff --git a/taglib/mpeg/id3v2/id3v2framefactory.cpp b/taglib/mpeg/id3v2/id3v2framefactory.cpp index 02b6cfaf..3595cc46 100644 --- a/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ b/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -37,6 +37,7 @@ #include "frames/uniquefileidentifierframe.h" #include "frames/unknownframe.h" #include "frames/generalencapsulatedobjectframe.h" +#include "frames/urllinkframe.h" using namespace TagLib; using namespace ID3v2; @@ -187,6 +188,19 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) if(frameID == "GEOB") return new GeneralEncapsulatedObjectFrame(data, header); + // URL link (frames 4.3) + + if(frameID.startsWith("W")) { + if(frameID != "WXXX") { + return new UrlLinkFrame(data, header); + } else { + UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header); + if(d->useDefaultEncoding) + f->setTextEncoding(d->defaultEncoding); + return f; + } + } + return new UnknownFrame(data, header); } diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index bfdf84bb..0cd43546 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace std; using namespace TagLib; @@ -39,6 +40,10 @@ class TestID3v2 : public CppUnit::TestFixture CPPUNIT_TEST(testParseEmptyUniqueFileIdentifierFrame); CPPUNIT_TEST(testBrokenFrame1); //CPPUNIT_TEST(testItunes24FrameSize); + CPPUNIT_TEST(testParseUrlLinkFrame); + CPPUNIT_TEST(testRenderUrlLinkFrame); + CPPUNIT_TEST(testParseUserUrlLinkFrame); + CPPUNIT_TEST(testRenderUserUrlLinkFrame); CPPUNIT_TEST_SUITE_END(); public: @@ -166,6 +171,56 @@ public: f.identifier()); } + void testParseUrlLinkFrame() + { + ID3v2::UrlLinkFrame f( + ByteVector("WOAF" // Frame ID + "\x00\x00\x00\x12" // Frame size + "\x00\x00" // Frame flags + "http://example.com", 28)); // URL + CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); + } + + void testRenderUrlLinkFrame() + { + ID3v2::UrlLinkFrame f("WOAF"); + f.setUrl("http://example.com"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("WOAF" // Frame ID + "\x00\x00\x00\x12" // Frame size + "\x00\x00" // Frame flags + "http://example.com", 28), // URL + f.render()); + } + + void testParseUserUrlLinkFrame() + { + ID3v2::UserUrlLinkFrame f( + ByteVector("WXXX" // Frame ID + "\x00\x00\x00\x17" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "foo\x00" // Description + "http://example.com", 33)); // URL + CPPUNIT_ASSERT_EQUAL(String("foo"), f.description()); + CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); + } + + void testRenderUserUrlLinkFrame() + { + ID3v2::UserUrlLinkFrame f; + f.setDescription("foo"); + f.setUrl("http://example.com"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("WXXX" // Frame ID + "\x00\x00\x00\x17" // Frame size + "\x00\x00" // Frame flags + "\x00" // Text encoding + "foo\x00" // Description + "http://example.com", 33), // URL + f.render()); + } + /*void testItunes24FrameSize() { MPEG::File f("data/005411.id3", false);