From 3741c3929506e9ac8a2ce96e0aa2b61f3b0a8210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Sat, 8 Jan 2011 10:36:26 +0000 Subject: [PATCH] Full read/write support for FLAC pictures NEEDS MORE TESTING BUG:218696 git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1212863 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- taglib/CMakeLists.txt | 1 - taglib/flac/flacfile.cpp | 259 +++++++----------- taglib/flac/flacmetadatablocks.cpp | 111 -------- taglib/flac/flacmetadatablocks.h | 69 ----- taglib/flac/flacpicture.cpp | 4 +- taglib/flac/flacpicture.h | 56 +++- taglib/mp4/mp4file.cpp | 4 +- tests/CMakeLists.txt | 1 - .../{empty_vorbis.ogg => empty_vorbis.oga} | Bin tests/test_flac.cpp | 140 +++++++++- tests/test_flacmetadatablocks.cpp | 41 --- tests/test_flacpicture.cpp | 1 - 12 files changed, 299 insertions(+), 388 deletions(-) delete mode 100644 taglib/flac/flacmetadatablocks.cpp delete mode 100644 taglib/flac/flacmetadatablocks.h rename tests/data/{empty_vorbis.ogg => empty_vorbis.oga} (100%) delete mode 100644 tests/test_flacmetadatablocks.cpp diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index c637091d..70da391d 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -96,7 +96,6 @@ flac/flacfile.cpp flac/flacpicture.cpp flac/flacproperties.cpp flac/flacmetadatablock.cpp -flac/flacmetadatablocks.cpp flac/flacunknownmetadatablock.cpp ) diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index cb402d5f..852c4f8c 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -37,22 +37,15 @@ #include "flacpicture.h" #include "flacfile.h" #include "flacmetadatablock.h" +#include "flacunknownmetadatablock.h" using namespace TagLib; namespace { enum { XiphIndex = 0, ID3v2Index = 1, ID3v1Index = 2 }; - enum { - StreamInfo = 0, - Padding, - Application, - SeekTable, - VorbisComment, - CueSheet, - PictureBlock - }; enum { MinPaddingLength = 4096 }; + enum { LastBlockFlag = 0x80 }; } class FLAC::File::FilePrivate @@ -70,13 +63,15 @@ public: scanned(false), hasXiphComment(false), hasID3v2(false), - hasID3v1(false) {} + hasID3v1(false) + { + for(uint i = 0; i < blocks.size(); i++) { + delete blocks[i]; + } + } ~FilePrivate() { - for(uint i = 0; i < pictureList.size(); i++) { - delete pictureList[i]; - } delete properties; } @@ -91,7 +86,7 @@ public: Properties *properties; ByteVector streamInfoData; ByteVector xiphCommentData; - List pictureList; + List blocks; long flacStart; long streamStart; @@ -147,113 +142,67 @@ bool FLAC::File::save() return false; } + if(!isValid()) { + debug("FLAC::File::save() -- Trying to save invalid file."); + return false; + } + // Create new vorbis comments Tag::duplicate(&d->tag, xiphComment(true), true); d->xiphCommentData = xiphComment()->render(false); - // A Xiph comment portion of the data stream starts with a 4-byte descriptor. - // The first byte indicates the frame type. The last three bytes are used - // to give the length of the data segment. Here we start + // Replace metadata blocks - ByteVector data = ByteVector::fromUInt(d->xiphCommentData.size()); - - data[0] = char(VorbisComment); - data.append(d->xiphCommentData); - - - // If file already have comment => find and update it - // if not => insert one - - // TODO: Search for padding and use that - - if(d->hasXiphComment) { - - long nextBlockOffset = d->flacStart; - bool isLastBlock = false; - - while(!isLastBlock) { - seek(nextBlockOffset); - - ByteVector header = readBlock(4); - char blockType = header[0] & 0x7f; - isLastBlock = (header[0] & 0x80) != 0; - uint blockLength = header.mid(1, 3).toUInt(); - - if(blockType == VorbisComment) { - - long paddingBreak = 0; - - if(!isLastBlock) { - paddingBreak = findPaddingBreak(nextBlockOffset + blockLength + 4, - nextBlockOffset + d->xiphCommentData.size() + 8, - &isLastBlock); - } - - uint paddingLength = 0; - - if(paddingBreak) { - - // There is space for comment and padding blocks without rewriting the - // whole file. Note: This cannot overflow. - - paddingLength = paddingBreak - (nextBlockOffset + d->xiphCommentData.size() + 8); - } - else { - - // Not enough space, so we will have to rewrite the whole file - // following this block - - paddingLength = d->xiphCommentData.size(); - - if(paddingLength < MinPaddingLength) - paddingLength = MinPaddingLength; - - paddingBreak = nextBlockOffset + blockLength + 4; - } - - ByteVector padding = ByteVector::fromUInt(paddingLength); - - padding[0] = 1; - - if(isLastBlock) - padding[0] |= 0x80; - - padding.resize(paddingLength + 4); - ByteVector pair(data); - pair.append(padding); - insert(pair, nextBlockOffset, paddingBreak - nextBlockOffset); - break; - } - - nextBlockOffset += blockLength + 4; + bool foundVorbisCommentBlock = false; + List newBlocks; + for(uint i = 0; i < d->blocks.size(); i++) { + MetadataBlock *block = d->blocks[i]; + if(block->code() == MetadataBlock::VorbisComment) { + // Set the new Vorbis Comment block + block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData); + foundVorbisCommentBlock = true; } - } - else { - - const long firstBlockOffset = d->flacStart; - seek(firstBlockOffset); - - ByteVector header = readBlock(4); - bool isLastBlock = (header[0] & 0x80) != 0; - uint blockLength = header.mid(1, 3).toUInt(); - - if(isLastBlock) { - - // If the first block was previously also the last block, then we want to - // mark it as no longer being the first block (the writeBlock() call) and - // then set the data for the block that we're about to write to mark our - // new block as the last block. - - seek(firstBlockOffset); - writeBlock(static_cast(header[0] & 0x7F)); - data[0] |= 0x80; + if(block->code() == MetadataBlock::Padding) { + continue; } - - insert(data, firstBlockOffset + blockLength + 4, 0); - d->hasXiphComment = true; + newBlocks.append(block); } + if(!foundVorbisCommentBlock) { + newBlocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)); + foundVorbisCommentBlock = true; + } + d->blocks = newBlocks; + + // Render data for the metadata blocks + + ByteVector data; + for(uint i = 0; i < newBlocks.size(); i++) { + FLAC::MetadataBlock *block = newBlocks[i]; + ByteVector blockData = block->render(); + ByteVector blockHeader = ByteVector::fromUInt(blockData.size()); + blockHeader[0] = block->code(); + data.append(blockHeader); + data.append(blockData); + } + + // Adjust the padding block(s) + + long originalLength = d->streamStart - d->flacStart; + int paddingLength = originalLength - data.size() - 4; + if (paddingLength < 0) { + paddingLength = MinPaddingLength; + } + ByteVector padding = ByteVector::fromUInt(paddingLength); + padding.resize(paddingLength + 4); + padding[0] = FLAC::MetadataBlock::Padding | LastBlockFlag; + data.append(padding); + + // Write the data to the file + + insert(data, d->flacStart, originalLength); + d->hasXiphComment = true; // Update ID3 tags @@ -410,13 +359,14 @@ void FLAC::File::scan() // First block should be the stream_info metadata - if(blockType != StreamInfo) { + if(blockType != MetadataBlock::StreamInfo) { debug("FLAC::File::scan() -- invalid FLAC stream"); setValid(false); return; } d->streamInfoData = readBlock(length); + d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData)); nextBlockOffset += length + 4; // Search through the remaining metadata @@ -427,27 +377,42 @@ void FLAC::File::scan() isLastBlock = (header[0] & 0x80) != 0; length = header.mid(1, 3).toUInt(); + ByteVector data = readBlock(length); + if(data.size() != length) { + debug("FLAC::File::scan() -- FLAC stream corrupted"); + setValid(false); + return; + } + + MetadataBlock *block = 0; + // Found the vorbis-comment - if(blockType == VorbisComment) { + if(blockType == MetadataBlock::VorbisComment) { if(!d->hasXiphComment) { - d->xiphCommentData = readBlock(length); + d->xiphCommentData = data; d->hasXiphComment = true; } else { debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one"); } } - else if(blockType == PictureBlock) { - ByteVector pictureData = readBlock(length); + else if(blockType == MetadataBlock::Picture) { FLAC::Picture *picture = new FLAC::Picture(); - if(picture->parse(pictureData)) { - addPicture(picture); + if(picture->parse(data)) { + block = picture; } else { - debug("FLAC::File::scan() -- invalid picture found"); + debug("FLAC::File::scan() -- invalid picture found, discarting"); } } + if(!block) { + block = new UnknownMetadataBlock(blockType, data); + } + if(block->code() != MetadataBlock::Padding) { + d->blocks.append(block); + } + nextBlockOffset += length + 4; if(nextBlockOffset >= File::length()) { @@ -496,51 +461,35 @@ long FLAC::File::findID3v2() return -1; } -long FLAC::File::findPaddingBreak(long nextBlockOffset, long targetOffset, bool *isLast) -{ - // Starting from nextBlockOffset, step over padding blocks to find the - // address of a block which is after targetOffset. Return zero if - // a non-padding block occurs before that point. - - while(true) { - seek(nextBlockOffset); - - ByteVector header = readBlock(4); - char blockType = header[0] & 0x7f; - bool isLastBlock = header[0] & 0x80; - uint length = header.mid(1, 3).toUInt(); - - if(blockType != Padding) - break; - - nextBlockOffset += 4 + length; - - if(nextBlockOffset >= targetOffset) { - *isLast = isLastBlock; - return nextBlockOffset; - } - - if(isLastBlock) - break; - } - - return 0; -} - List FLAC::File::pictureList() { - return d->pictureList; + List pictures; + for(uint i = 0; i < d->blocks.size(); i++) { + Picture *picture = dynamic_cast(d->blocks[i]); + if(picture) { + pictures.append(picture); + } + } + return pictures; } void FLAC::File::addPicture(Picture *picture) { - d->pictureList.append(picture); + d->blocks.append(picture); } void FLAC::File::removePictures() { - for(uint i = 0; i < d->pictureList.size(); i++) - delete d->pictureList[i]; - d->pictureList.clear(); + List newBlocks; + for(uint i = 0; i < d->blocks.size(); i++) { + Picture *picture = dynamic_cast(d->blocks[i]); + if(picture) { + delete picture; + } + else { + newBlocks.append(d->blocks[i]); + } + } + d->blocks = newBlocks; } diff --git a/taglib/flac/flacmetadatablocks.cpp b/taglib/flac/flacmetadatablocks.cpp deleted file mode 100644 index e5bd638e..00000000 --- a/taglib/flac/flacmetadatablocks.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * 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/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include "flacfile.h" -#include "flacunknownmetadatablock.h" -#include "flacmetadatablock.h" -#include "flacmetadatablocks.h" - -using namespace TagLib; - -class FLAC::MetadataBlocks::MetadataBlocksPrivate -{ -public: - MetadataBlocksPrivate() {} - - List blocks; -}; - -FLAC::MetadataBlocks::MetadataBlocks() -{ - d = new MetadataBlocksPrivate(); -} - -FLAC::MetadataBlocks::~MetadataBlocks() -{ - delete d; -} - -const List &FLAC::MetadataBlocks::metadataBlockList() const -{ - return d->blocks; -} - -bool FLAC::MetadataBlocks::read(FLAC::File *file) -{ - bool isLastBlock = false; - while(!isLastBlock) { - ByteVector header = file->readBlock(4); - if(header.size() != 4) { - debug("FLAC::MetadataBlocks::read -- Unable to read 4 bytes long header"); - return false; - } - char blockType = header[0] & 0x7f; - isLastBlock = (header[0] & 0x80) != 0; - uint length = header.mid(1, 3).toUInt(); - ByteVector data = file->readBlock(length); - if(data.size() != length) { - debug("FLAC::MetadataBlocks::read -- Unable to read " + String::number(length) + " bytes long block body"); - return false; - } - if(blockType != FLAC::MetadataBlock::Padding) { - FLAC::MetadataBlock *block = new FLAC::UnknownMetadataBlock(blockType, data); - d->blocks.append(block); - } - } - return true; -} - -ByteVector FLAC::MetadataBlocks::render(int originalLength) const -{ - ByteVector result; - for(uint i = 0; i < d->blocks.size(); i++) { - FLAC::MetadataBlock *block = d->blocks[i]; - if(block->code() == FLAC::MetadataBlock::Padding) - continue; - ByteVector data = block->render(); - ByteVector header = ByteVector::fromUInt(data.size()); - header[0] = block->code(); - result.append(header); - result.append(data); - } - int paddingLength = originalLength - result.size() - 4; - // We have to resize the file, add some padding - if (paddingLength < 0) { - paddingLength = 4096; - } - ByteVector padding = ByteVector::fromUInt(paddingLength); - padding.resize(paddingLength + 4); - padding[0] = FLAC::MetadataBlock::Padding | 0x80; - result.append(padding); - return result; -} - diff --git a/taglib/flac/flacmetadatablocks.h b/taglib/flac/flacmetadatablocks.h deleted file mode 100644 index e029c289..00000000 --- a/taglib/flac/flacmetadatablocks.h +++ /dev/null @@ -1,69 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * 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_FLACMETADATABLOCKS_H -#define TAGLIB_FLACMETADATABLOCKS_H - -#include "tlist.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace FLAC { - - class File; - - class TAGLIB_EXPORT MetadataBlocks - { - public: - MetadataBlocks(); - virtual ~MetadataBlocks(); - - /*! - * Read the blocks from a file. - */ - bool read(File *file); - - /*! - * Render the blocks into a byte vector. - */ - ByteVector render(int originalLength) const; - - const List &metadataBlockList() const; - - private: - MetadataBlocks(const MetadataBlocks &item); - MetadataBlocks &operator=(const MetadataBlocks &item); - - class MetadataBlocksPrivate; - MetadataBlocksPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/flac/flacpicture.cpp b/taglib/flac/flacpicture.cpp index 40e69b12..44ef3867 100644 --- a/taglib/flac/flacpicture.cpp +++ b/taglib/flac/flacpicture.cpp @@ -37,7 +37,7 @@ class FLAC::Picture::PicturePrivate { public: PicturePrivate() : - type(ID3v2::AttachedPictureFrame::Other), + type(FLAC::Picture::Other), width(0), height(0), colorDepth(0), @@ -83,7 +83,7 @@ bool FLAC::Picture::parse(const ByteVector &data) } int pos = 0; - d->type = TagLib::ID3v2::AttachedPictureFrame::Type(data.mid(pos, 4).toUInt()); + d->type = FLAC::Picture::Type(data.mid(pos, 4).toUInt()); pos += 4; uint mimeTypeLength = data.mid(pos, 4).toUInt(); pos += 4; diff --git a/taglib/flac/flacpicture.h b/taglib/flac/flacpicture.h index 447bcaf8..22adc36e 100644 --- a/taglib/flac/flacpicture.h +++ b/taglib/flac/flacpicture.h @@ -27,9 +27,9 @@ #define TAGLIB_FLACPICTURE_H #include "tlist.h" +#include "tstring.h" #include "tbytevector.h" #include "taglib_export.h" -#include "attachedpictureframe.h" #include "flacmetadatablock.h" namespace TagLib { @@ -39,7 +39,54 @@ namespace TagLib { class TAGLIB_EXPORT Picture : public MetadataBlock { public: - typedef ID3v2::AttachedPictureFrame::Type Type; + + /*! + * This describes the function or content of the picture. + */ + enum Type { + //! A type not enumerated below + Other = 0x00, + //! 32x32 PNG image that should be used as the file icon + FileIcon = 0x01, + //! File icon of a different size or format + OtherFileIcon = 0x02, + //! Front cover image of the album + FrontCover = 0x03, + //! Back cover image of the album + BackCover = 0x04, + //! Inside leaflet page of the album + LeafletPage = 0x05, + //! Image from the album itself + Media = 0x06, + //! Picture of the lead artist or soloist + LeadArtist = 0x07, + //! Picture of the artist or performer + Artist = 0x08, + //! Picture of the conductor + Conductor = 0x09, + //! Picture of the band or orchestra + Band = 0x0A, + //! Picture of the composer + Composer = 0x0B, + //! Picture of the lyricist or text writer + Lyricist = 0x0C, + //! Picture of the recording location or studio + RecordingLocation = 0x0D, + //! Picture of the artists during recording + DuringRecording = 0x0E, + //! Picture of the artists during performance + DuringPerformance = 0x0F, + //! Picture from a movie or video related to the track + MovieScreenCapture = 0x10, + //! Picture of a large, coloured fish + ColouredFish = 0x11, + //! Illustration related to the track + Illustration = 0x12, + //! Logo of the band or performer + BandLogo = 0x13, + //! Logo of the publisher (record company) + PublisherLogo = 0x14 + }; Picture(); Picture(const ByteVector &data); @@ -135,10 +182,13 @@ namespace TagLib { int code() const; /*! - * Render the content of the block. + * Render the content to the FLAC picture block format. */ ByteVector render() const; + /*! + * Parse the picture data in the FLAC picture block format. + */ bool parse(const ByteVector &rawData); private: diff --git a/taglib/mp4/mp4file.cpp b/taglib/mp4/mp4file.cpp index 1e4bd4db..fcaa67d4 100644 --- a/taglib/mp4/mp4file.cpp +++ b/taglib/mp4/mp4file.cpp @@ -134,8 +134,10 @@ MP4::File::save() return false; } - if(!isValid()) + if(!isValid()) { + debug("MP4::File::save() -- Trying to save invalid file."); return false; + } return d->tag->save(); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f06f2a4d..86408af0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,7 +41,6 @@ SET(test_runner_SRCS test_oggflac.cpp test_flac.cpp test_flacpicture.cpp - test_flacmetadatablocks.cpp test_flacunknownmetadatablock.cpp test_ape.cpp test_apetag.cpp diff --git a/tests/data/empty_vorbis.ogg b/tests/data/empty_vorbis.oga similarity index 100% rename from tests/data/empty_vorbis.ogg rename to tests/data/empty_vorbis.oga diff --git a/tests/test_flac.cpp b/tests/test_flac.cpp index d14a597b..1f50666c 100644 --- a/tests/test_flac.cpp +++ b/tests/test_flac.cpp @@ -15,7 +15,11 @@ class TestFLAC : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(TestFLAC); CPPUNIT_TEST(testSignature); CPPUNIT_TEST(testMultipleCommentBlocks); - CPPUNIT_TEST(testPicture); + CPPUNIT_TEST(testReadPicture); + CPPUNIT_TEST(testAddPicture); + CPPUNIT_TEST(testReplacePicture); + CPPUNIT_TEST(testRemoveAllPictures); + CPPUNIT_TEST(testRepeatedSave); CPPUNIT_TEST_SUITE_END(); public: @@ -42,7 +46,7 @@ public: delete f; } - void testPicture() + void testReadPicture() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); @@ -52,7 +56,7 @@ public: CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); FLAC::Picture *pic = lst.front(); - CPPUNIT_ASSERT_EQUAL(3, int(pic->type())); + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); CPPUNIT_ASSERT_EQUAL(1, pic->width()); CPPUNIT_ASSERT_EQUAL(1, pic->height()); CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); @@ -62,6 +66,136 @@ public: CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic->data().size()); } + void testAddPicture() + { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + FLAC::File *f = new FLAC::File(newname.c_str()); + List lst = f->pictureList(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); + + 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->addPicture(newpic); + f->save(); + + f = new FLAC::File(newname.c_str()); + lst = f->pictureList(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), lst.size()); + + FLAC::Picture *pic = lst[0]; + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(1, pic->width()); + CPPUNIT_ASSERT_EQUAL(1, pic->height()); + CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic->data().size()); + + pic = lst[1]; + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(5, pic->width()); + CPPUNIT_ASSERT_EQUAL(6, pic->height()); + CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); + } + + void testReplacePicture() + { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + FLAC::File *f = new FLAC::File(newname.c_str()); + List lst = f->pictureList(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); + + 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->removePictures(); + f->addPicture(newpic); + f->save(); + + f = new FLAC::File(newname.c_str()); + lst = f->pictureList(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); + + FLAC::Picture *pic = lst[0]; + CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); + CPPUNIT_ASSERT_EQUAL(5, pic->width()); + CPPUNIT_ASSERT_EQUAL(6, pic->height()); + CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); + CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); + CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); + CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); + CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); + } + + void testRemoveAllPictures() + { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + FLAC::File *f = new FLAC::File(newname.c_str()); + List lst = f->pictureList(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); + + 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->removePictures(); + f->addPicture(newpic); + f->save(); + + f = new FLAC::File(newname.c_str()); + lst = f->pictureList(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), lst.size()); + } + + void testRepeatedSave() + { + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + FLAC::File *f = new FLAC::File(newname.c_str()); + Tag *tag = f->tag(); + CPPUNIT_ASSERT_EQUAL(String("Silence"), tag->title()); + tag->setTitle("NEW TITLE"); + f->save(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE"), tag->title()); + tag->setTitle("NEW TITLE 2"); + f->save(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title()); + + f = new FLAC::File(newname.c_str()); + tag = f->tag(); + CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title()); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC); diff --git a/tests/test_flacmetadatablocks.cpp b/tests/test_flacmetadatablocks.cpp deleted file mode 100644 index 59954cad..00000000 --- a/tests/test_flacmetadatablocks.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestFLACMetadataBlocks : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestFLACMetadataBlocks); - CPPUNIT_TEST(testRead); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testRead() - { - FLAC::File f("data/silence-44-s.flac"); - FLAC::MetadataBlocks b; - f.seek(4); - b.read(&f); - List blocks = b.metadataBlockList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(5), blocks.size()); - CPPUNIT_ASSERT_EQUAL(0 + FLAC::MetadataBlock::StreamInfo, blocks[0]->code()); - CPPUNIT_ASSERT_EQUAL(0 + FLAC::MetadataBlock::SeekTable, blocks[1]->code()); - CPPUNIT_ASSERT_EQUAL(0 + FLAC::MetadataBlock::VorbisComment, blocks[2]->code()); - CPPUNIT_ASSERT_EQUAL(0 + FLAC::MetadataBlock::CueSheet, blocks[3]->code()); - CPPUNIT_ASSERT_EQUAL(0 + FLAC::MetadataBlock::Picture, blocks[4]->code()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACMetadataBlocks); - diff --git a/tests/test_flacpicture.cpp b/tests/test_flacpicture.cpp index 180455cf..5ed13951 100644 --- a/tests/test_flacpicture.cpp +++ b/tests/test_flacpicture.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include "utils.h" using namespace std;