]> granicus.if.org Git - taglib/commitdiff
Add FLAC::Picture support to Xiph Comment
authorSander Jansen <s.jansen@gmail.com>
Sat, 16 May 2015 19:10:24 +0000 (14:10 -0500)
committerSander Jansen <s.jansen@gmail.com>
Thu, 12 Nov 2015 14:50:34 +0000 (08:50 -0600)
taglib/ogg/xiphcomment.cpp
taglib/ogg/xiphcomment.h
tests/test_ogg.cpp

index 9462607f4c1d432e4bd6ca7e80dd631c2cfeeedf..c307e618d88f4143913a2169e9f872577c576830 100644 (file)
 #include <tbytevector.h>
 #include <tdebug.h>
 
+#include <flacpicture.h>
 #include <xiphcomment.h>
 #include <tpropertymap.h>
 
 using namespace TagLib;
 
+
+typedef List<FLAC::Picture*> PictureList;
+
 class Ogg::XiphComment::XiphCommentPrivate
 {
 public:
   FieldListMap fieldListMap;
   String vendorID;
   String commentField;
+  PictureList pictureList;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -181,6 +186,8 @@ TagLib::uint Ogg::XiphComment::fieldCount() const
   for(; it != d->fieldListMap.end(); ++it)
     count += (*it).second.size();
 
+  count += d->pictureList.size();
+
   return count;
 }
 
@@ -275,6 +282,36 @@ bool Ogg::XiphComment::contains(const String &key) const
   return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty();
 }
 
+void Ogg::XiphComment::removePicture(FLAC::Picture *picture, bool del)
+{
+  List<FLAC::Picture *>::Iterator it = d->pictureList.find(picture);
+  if(it != d->pictureList.end())
+    d->pictureList.erase(it);
+
+  if(del)
+    delete picture;
+}
+
+void Ogg::XiphComment::removePictures()
+{
+  PictureList newList;
+  for(uint i = 0; i < d->pictureList.size(); i++) {
+    delete d->pictureList[i];
+  }
+  d->pictureList = newList;
+}
+
+void Ogg::XiphComment::addPicture(FLAC::Picture * picture)
+{
+  d->pictureList.append(picture);
+}
+
+
+List<FLAC::Picture *> Ogg::XiphComment::pictureList()
+{
+  return d->pictureList;
+}
+
 ByteVector Ogg::XiphComment::render() const
 {
   return render(true);
@@ -321,6 +358,13 @@ ByteVector Ogg::XiphComment::render(bool addFramingBit) const
     }
   }
 
+  for(PictureList::ConstIterator it = d->pictureList.begin(); it != d->pictureList.end(); ++it) {
+    ByteVector picture = (*it)->render().toBase64();
+    data.append(ByteVector::fromUInt(picture.size()+23,false));
+    data.append("METADATA_BLOCK_PICTURE=");
+    data.append(picture);
+  }
+
   // Append the "framing bit".
 
   if(addFramingBit)
@@ -363,20 +407,41 @@ void Ogg::XiphComment::parse(const ByteVector &data)
     const uint commentLength = data.toUInt(pos, false);
     pos += 4;
 
-    String comment = String(data.mid(pos, commentLength), String::UTF8);
-    pos += commentLength;
-    if(pos > data.size()) {
-      break;
-    }
+    ByteVector entry = data.mid(pos, commentLength);
 
-    int commentSeparatorPosition = comment.find("=");
-    if(commentSeparatorPosition == -1) {
+    // Don't go past data end
+    pos+=commentLength;
+    if (pos>data.size())
       break;
+
+    // Handle Pictures separately
+    if(entry.startsWith("METADATA_BLOCK_PICTURE=")) {
+
+      // Decode base64 picture data
+      ByteVector picturedata = entry.mid(23, entry.size()-23).fromBase64();
+
+      if(picturedata.size()==0) {
+        debug("Empty picture data. Discarding content");
+        continue;
+        }
+
+      FLAC::Picture * picture = new FLAC::Picture();
+      if(picture->parse(picturedata))
+        d->pictureList.append(picture);
+      else
+        debug("Unable to parse METADATA_BLOCK_PICTURE. Discarding content.");
     }
+    else {
 
-    String key = comment.substr(0, commentSeparatorPosition);
-    String value = comment.substr(commentSeparatorPosition + 1);
+      // Check for field separator
+      int sep = entry.find('=');
+      if (sep == -1)
+        break;
 
-    addField(key, value, false);
+      // Parse key and value
+      String key = String(entry.mid(0,sep), String::UTF8);
+      String value = String(entry.mid(sep+1, commentLength-sep), String::UTF8);
+      addField(key, value, false);
+    }
   }
 }
index 54f3070bf39de621bf8fcdeafb91e867829cbd5e..8fcc6873e2d545848f971cb0d7aeef855daaa315 100644 (file)
@@ -32,6 +32,7 @@
 #include "tstring.h"
 #include "tstringlist.h"
 #include "tbytevector.h"
+#include "flacpicture.h"
 #include "taglib_export.h"
 
 namespace TagLib {
@@ -205,6 +206,31 @@ namespace TagLib {
        */
       ByteVector render(bool addFramingBit) const;
 
+
+      /*!
+       * Returns a list of pictures attached to the xiph comment.
+       */
+      List<FLAC::Picture *> pictureList();
+
+      /*!
+       * Removes an picture. If \a del is true the picture's memory
+       * will be freed; if it is false, it must be deleted by the user.
+       */
+      void removePicture(FLAC::Picture *picture, bool del = true);
+
+      /*!
+       * Remove all pictures.
+       */
+      void removePictures();
+
+      /*!
+       * Add a new picture to the comment block. The comment block takes ownership of the
+       * picture and will handle freeing its memory.
+       *
+       * \note The file will be saved only after calling save().
+       */
+      void addPicture(FLAC::Picture *picture);
+
     protected:
       /*!
        * Reads the tag from the file specified in the constructor and fills the
index 210fca2f0999df9112ab066eefce4dacb9ed3105..05b23f644fee8f4b21a800d91245894f1b1fbe06 100644 (file)
@@ -21,6 +21,7 @@ class TestOGG : public CppUnit::TestFixture
   CPPUNIT_TEST(testDictInterface1);
   CPPUNIT_TEST(testDictInterface2);
   CPPUNIT_TEST(testAudioProperties);
+  CPPUNIT_TEST(testPicture);
   CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -134,6 +135,33 @@ public:
     CPPUNIT_ASSERT_EQUAL(112000, f.audioProperties()->bitrateNominal());
     CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrateMinimum());
   }
+
+  void testPicture()
+  {
+    ScopedFileCopy copy("empty", ".ogg");
+    string newname = copy.fileName();
+
+    Vorbis::File *f = new Vorbis::File(newname.c_str());
+    FLAC::Picture *newpic = new FLAC::Picture();
+    newpic->setType(FLAC::Picture::BackCover);
+    newpic->setWidth(5);
+    newpic->setHeight(6);
+    newpic->setColorDepth(16);
+    newpic->setNumColors(7);
+    newpic->setMimeType("image/jpeg");
+    newpic->setDescription("new image");
+    newpic->setData("JPEG data");
+    f->tag()->addPicture(newpic);
+    f->save();
+    delete f;
+
+    f = new Vorbis::File(newname.c_str());
+    List<FLAC::Picture *> lst = f->tag()->pictureList();
+    CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size());
+    delete f;
+  }
+
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestOGG);