#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;
};
////////////////////////////////////////////////////////////////////////////////
for(; it != d->fieldListMap.end(); ++it)
count += (*it).second.size();
+ count += d->pictureList.size();
+
return count;
}
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);
}
}
+ 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)
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);
+ }
}
}
#include "tstring.h"
#include "tstringlist.h"
#include "tbytevector.h"
+#include "flacpicture.h"
#include "taglib_export.h"
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
CPPUNIT_TEST(testDictInterface1);
CPPUNIT_TEST(testDictInterface2);
CPPUNIT_TEST(testAudioProperties);
+ CPPUNIT_TEST(testPicture);
CPPUNIT_TEST_SUITE_END();
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);