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
This commit is contained in:
Lukáš Lalinský
2011-01-08 10:36:26 +00:00
parent d16be3fa98
commit 3741c39295
12 changed files with 299 additions and 388 deletions

View File

@ -96,7 +96,6 @@ flac/flacfile.cpp
flac/flacpicture.cpp
flac/flacproperties.cpp
flac/flacmetadatablock.cpp
flac/flacmetadatablocks.cpp
flac/flacunknownmetadatablock.cpp
)

View File

@ -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<Picture *> pictureList;
List<MetadataBlock *> 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<MetadataBlock *> 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<char>(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::Picture *> FLAC::File::pictureList()
{
return d->pictureList;
List<Picture *> pictures;
for(uint i = 0; i < d->blocks.size(); i++) {
Picture *picture = dynamic_cast<Picture *>(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<MetadataBlock *> newBlocks;
for(uint i = 0; i < d->blocks.size(); i++) {
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
if(picture) {
delete picture;
}
else {
newBlocks.append(d->blocks[i]);
}
}
d->blocks = newBlocks;
}

View File

@ -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 <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "flacfile.h"
#include "flacunknownmetadatablock.h"
#include "flacmetadatablock.h"
#include "flacmetadatablocks.h"
using namespace TagLib;
class FLAC::MetadataBlocks::MetadataBlocksPrivate
{
public:
MetadataBlocksPrivate() {}
List<MetadataBlock *> blocks;
};
FLAC::MetadataBlocks::MetadataBlocks()
{
d = new MetadataBlocksPrivate();
}
FLAC::MetadataBlocks::~MetadataBlocks()
{
delete d;
}
const List<FLAC::MetadataBlock *> &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;
}

View File

@ -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<MetadataBlock *> &metadataBlockList() const;
private:
MetadataBlocks(const MetadataBlocks &item);
MetadataBlocks &operator=(const MetadataBlocks &item);
class MetadataBlocksPrivate;
MetadataBlocksPrivate *d;
};
}
}
#endif

View File

@ -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;

View File

@ -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:

View File

@ -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();
}

View File

@ -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

View File

@ -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<FLAC::Picture *> 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<FLAC::Picture *> 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<FLAC::Picture *> 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);

View File

@ -1,41 +0,0 @@
#include <cppunit/extensions/HelperMacros.h>
#include <string>
#include <stdio.h>
#include <tag.h>
#include <tstringlist.h>
#include <tbytevectorlist.h>
#include <flacfile.h>
#include <flacmetadatablock.h>
#include <flacmetadatablocks.h>
#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<FLAC::MetadataBlock *> 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);

View File

@ -6,7 +6,6 @@
#include <tbytevectorlist.h>
#include <flacfile.h>
#include <flacmetadatablock.h>
#include <flacmetadatablocks.h>
#include "utils.h"
using namespace std;