Add FLAC::Picture support to Xiph Comment

This commit is contained in:
Sander Jansen
2015-05-16 14:10:24 -05:00
parent 7bbf5a2e79
commit 0c14bd0ed0
3 changed files with 130 additions and 11 deletions

View File

@ -26,17 +26,22 @@
#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()) {
ByteVector entry = data.mid(pos, commentLength);
// 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 {
int commentSeparatorPosition = comment.find("=");
if(commentSeparatorPosition == -1) {
break;
// Check for field separator
int sep = entry.find('=');
if (sep == -1)
break;
// 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);
}
String key = comment.substr(0, commentSeparatorPosition);
String value = comment.substr(commentSeparatorPosition + 1);
addField(key, value, false);
}
}

View 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

View 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);