mirror of
https://github.com/taglib/taglib.git
synced 2025-07-18 04:54:19 -04:00
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:
@ -96,7 +96,6 @@ flac/flacfile.cpp
|
||||
flac/flacpicture.cpp
|
||||
flac/flacproperties.cpp
|
||||
flac/flacmetadatablock.cpp
|
||||
flac/flacmetadatablocks.cpp
|
||||
flac/flacunknownmetadatablock.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<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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <tbytevectorlist.h>
|
||||
#include <flacfile.h>
|
||||
#include <flacmetadatablock.h>
|
||||
#include <flacmetadatablocks.h>
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
Reference in New Issue
Block a user