Audio file detection by content

This commit is contained in:
Jonas Kvinge
2018-05-10 15:29:28 +02:00
parent 7b2d1d95d3
commit 5392cc4109
232 changed files with 55355 additions and 133 deletions

174
3rdparty/taglib/riff/aiff/aifffile.cpp vendored Normal file
View File

@@ -0,0 +1,174 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "aifffile.h"
using namespace TagLib;
class RIFF::AIFF::File::FilePrivate
{
public:
FilePrivate() :
properties(0),
tag(0),
hasID3v2(false) {}
~FilePrivate()
{
delete properties;
delete tag;
}
Properties *properties;
ID3v2::Tag *tag;
bool hasID3v2;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool RIFF::AIFF::File::isSupported(IOStream *stream)
{
// An AIFF file has to start with "FORM????AIFF" or "FORM????AIFC".
const ByteVector id = Utils::readHeader(stream, 12, false);
return (id.startsWith("FORM") && (id.containsAt("AIFF", 8) || id.containsAt("AIFC", 8)));
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
RIFF::AIFF::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
RIFF::File(file, BigEndian),
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
RIFF::AIFF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
RIFF::File(stream, BigEndian),
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
RIFF::AIFF::File::~File()
{
delete d;
}
ID3v2::Tag *RIFF::AIFF::File::tag() const
{
return d->tag;
}
PropertyMap RIFF::AIFF::File::properties() const
{
return d->tag->properties();
}
void RIFF::AIFF::File::removeUnsupportedProperties(const StringList &unsupported)
{
d->tag->removeUnsupportedProperties(unsupported);
}
PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
RIFF::AIFF::Properties *RIFF::AIFF::File::audioProperties() const
{
return d->properties;
}
bool RIFF::AIFF::File::save()
{
if(readOnly()) {
debug("RIFF::AIFF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("RIFF::AIFF::File::save() -- Trying to save invalid file.");
return false;
}
if(d->hasID3v2) {
removeChunk("ID3 ");
removeChunk("id3 ");
d->hasID3v2 = false;
}
if(tag() && !tag()->isEmpty()) {
setChunkData("ID3 ", d->tag->render());
d->hasID3v2 = true;
}
return true;
}
bool RIFF::AIFF::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void RIFF::AIFF::File::read(bool readProperties)
{
for(unsigned int i = 0; i < chunkCount(); ++i) {
const ByteVector name = chunkName(i);
if(name == "ID3 " || name == "id3 ") {
if(!d->tag) {
d->tag = new ID3v2::Tag(this, chunkOffset(i));
d->hasID3v2 = true;
}
else {
debug("RIFF::AIFF::File::read() - Duplicate ID3v2 tag found.");
}
}
}
if(!d->tag)
d->tag = new ID3v2::Tag();
if(readProperties)
d->properties = new Properties(this, Properties::Average);
}

152
3rdparty/taglib/riff/aiff/aifffile.h vendored Normal file
View File

@@ -0,0 +1,152 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_AIFFFILE_H
#define TAGLIB_AIFFFILE_H
#include "rifffile.h"
#include "id3v2tag.h"
#include "aiffproperties.h"
namespace TagLib {
namespace RIFF {
//! An implementation of AIFF metadata
/*!
* This is implementation of AIFF metadata.
*
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
* chunk as well as properties from the file.
*/
namespace AIFF {
//! An implementation of TagLib::File with AIFF specific methods
/*!
* This implements and provides an interface for AIFF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to AIFF files.
*/
class TAGLIB_EXPORT File : public TagLib::RIFF::File
{
public:
/*!
* Constructs an AIFF file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Constructs an AIFF file from \a stream. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
* on disk actually has an ID3v2 tag.
*
* \see hasID3v2Tag()
*/
virtual ID3v2::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the AIFF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
/*!
* Saves the file.
*/
virtual bool save();
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
/*!
* Check if the given \a stream can be opened as an AIFF file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties);
friend class Properties;
class FilePrivate;
FilePrivate *d;
};
}
}
}
#endif

View File

@@ -0,0 +1,192 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "aifffile.h"
#include "aiffproperties.h"
using namespace TagLib;
class RIFF::AIFF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
bitsPerSample(0),
sampleFrames(0) {}
int length;
int bitrate;
int sampleRate;
int channels;
int bitsPerSample;
ByteVector compressionType;
String compressionName;
unsigned int sampleFrames;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
RIFF::AIFF::Properties::Properties(const ByteVector &, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
debug("RIFF::AIFF::Properties::Properties() - This constructor is no longer used.");
}
RIFF::AIFF::Properties::Properties(File *file, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
read(file);
}
RIFF::AIFF::Properties::~Properties()
{
delete d;
}
int RIFF::AIFF::Properties::length() const
{
return lengthInSeconds();
}
int RIFF::AIFF::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int RIFF::AIFF::Properties::lengthInMilliseconds() const
{
return d->length;
}
int RIFF::AIFF::Properties::bitrate() const
{
return d->bitrate;
}
int RIFF::AIFF::Properties::sampleRate() const
{
return d->sampleRate;
}
int RIFF::AIFF::Properties::channels() const
{
return d->channels;
}
int RIFF::AIFF::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
int RIFF::AIFF::Properties::sampleWidth() const
{
return bitsPerSample();
}
unsigned int RIFF::AIFF::Properties::sampleFrames() const
{
return d->sampleFrames;
}
bool RIFF::AIFF::Properties::isAiffC() const
{
return (!d->compressionType.isEmpty());
}
ByteVector RIFF::AIFF::Properties::compressionType() const
{
return d->compressionType;
}
String RIFF::AIFF::Properties::compressionName() const
{
return d->compressionName;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void RIFF::AIFF::Properties::read(File *file)
{
ByteVector data;
unsigned int streamLength = 0;
for(unsigned int i = 0; i < file->chunkCount(); i++) {
const ByteVector name = file->chunkName(i);
if(name == "COMM") {
if(data.isEmpty())
data = file->chunkData(i);
else
debug("RIFF::AIFF::Properties::read() - Duplicate 'COMM' chunk found.");
}
else if(name == "SSND") {
if(streamLength == 0)
streamLength = file->chunkDataSize(i) + file->chunkPadding(i);
else
debug("RIFF::AIFF::Properties::read() - Duplicate 'SSND' chunk found.");
}
}
if(data.size() < 18) {
debug("RIFF::AIFF::Properties::read() - 'COMM' chunk not found or too short.");
return;
}
if(streamLength == 0) {
debug("RIFF::AIFF::Properties::read() - 'SSND' chunk not found.");
return;
}
d->channels = data.toShort(0U);
d->sampleFrames = data.toUInt(2U);
d->bitsPerSample = data.toShort(6U);
const long double sampleRate = data.toFloat80BE(8);
if(sampleRate >= 1.0)
d->sampleRate = static_cast<int>(sampleRate + 0.5);
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
}
if(data.size() >= 23) {
d->compressionType = data.mid(18, 4);
d->compressionName
= String(data.mid(23, static_cast<unsigned char>(data[22])), String::Latin1);
}
}

View File

@@ -0,0 +1,166 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_AIFFPROPERTIES_H
#define TAGLIB_AIFFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace RIFF {
namespace AIFF {
class File;
//! An implementation of audio property reading for AIFF
/*!
* This reads the data from an AIFF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
* Create an instance of AIFF::Properties with the data read from the
* ByteVector \a data.
*
* \deprecated
*/
Properties(const ByteVector &data, ReadStyle style);
/*!
* Create an instance of AIFF::Properties with the data read from the
* AIFF::File \a file.
*/
Properties(File *file, ReadStyle style);
/*!
* Destroys this AIFF::Properties instance.
*/
virtual ~Properties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns the number of bits per audio sample.
*/
int bitsPerSample() const;
/*!
* Returns the number of bits per audio sample.
*
* \note This method is just an alias of bitsPerSample().
*
* \deprecated
*/
int sampleWidth() const;
/*!
* Returns the number of sample frames
*/
unsigned int sampleFrames() const;
/*!
* Returns true if the file is in AIFF-C format, false if AIFF format.
*/
bool isAiffC() const;
/*!
* Returns the compression type of the AIFF-C file. For example, "NONE" for
* not compressed, "ACE2" for ACE 2-to-1.
*
* If the file is in AIFF format, always returns an empty vector.
*
* \see isAiffC()
*/
ByteVector compressionType() const;
/*!
* Returns the concrete compression name of the AIFF-C file.
*
* If the file is in AIFF format, always returns an empty string.
*
* \see isAiffC()
*/
String compressionName() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(File *file);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
}
#endif

361
3rdparty/taglib/riff/rifffile.cpp vendored Normal file
View File

@@ -0,0 +1,361 @@
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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/ *
***************************************************************************/
#include <algorithm>
#include <vector>
#include <tbytevector.h>
#include <tdebug.h>
#include <tstring.h>
#include "rifffile.h"
#include "riffutils.h"
using namespace TagLib;
struct Chunk
{
ByteVector name;
unsigned int offset;
unsigned int size;
unsigned int padding;
};
class RIFF::File::FilePrivate
{
public:
FilePrivate(Endianness endianness) :
endianness(endianness),
size(0),
sizeOffset(0) {}
const Endianness endianness;
unsigned int size;
long sizeOffset;
std::vector<Chunk> chunks;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
RIFF::File::~File()
{
delete d;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
RIFF::File::File(FileName file, Endianness endianness) :
TagLib::File(file),
d(new FilePrivate(endianness))
{
if(isOpen())
read();
}
RIFF::File::File(IOStream *stream, Endianness endianness) :
TagLib::File(stream),
d(new FilePrivate(endianness))
{
if(isOpen())
read();
}
unsigned int RIFF::File::riffSize() const
{
return d->size;
}
unsigned int RIFF::File::chunkCount() const
{
return static_cast<unsigned int>(d->chunks.size());
}
unsigned int RIFF::File::chunkDataSize(unsigned int i) const
{
if(i >= d->chunks.size()) {
debug("RIFF::File::chunkDataSize() - Index out of range. Returning 0.");
return 0;
}
return d->chunks[i].size;
}
unsigned int RIFF::File::chunkOffset(unsigned int i) const
{
if(i >= d->chunks.size()) {
debug("RIFF::File::chunkOffset() - Index out of range. Returning 0.");
return 0;
}
return d->chunks[i].offset;
}
unsigned int RIFF::File::chunkPadding(unsigned int i) const
{
if(i >= d->chunks.size()) {
debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
return 0;
}
return d->chunks[i].padding;
}
ByteVector RIFF::File::chunkName(unsigned int i) const
{
if(i >= d->chunks.size()) {
debug("RIFF::File::chunkName() - Index out of range. Returning an empty vector.");
return ByteVector();
}
return d->chunks[i].name;
}
ByteVector RIFF::File::chunkData(unsigned int i)
{
if(i >= d->chunks.size()) {
debug("RIFF::File::chunkData() - Index out of range. Returning an empty vector.");
return ByteVector();
}
seek(d->chunks[i].offset);
return readBlock(d->chunks[i].size);
}
void RIFF::File::setChunkData(unsigned int i, const ByteVector &data)
{
if(i >= d->chunks.size()) {
debug("RIFF::File::setChunkData() - Index out of range.");
return;
}
// Now update the specific chunk
std::vector<Chunk>::iterator it = d->chunks.begin();
std::advance(it, i);
const long long originalSize = static_cast<long long>(it->size) + it->padding;
writeChunk(it->name, data, it->offset - 8, it->size + it->padding + 8);
it->size = data.size();
it->padding = data.size() % 2;
const long long diff = static_cast<long long>(it->size) + it->padding - originalSize;
// Now update the internal offsets
for(++it; it != d->chunks.end(); ++it)
it->offset += static_cast<int>(diff);
// Update the global size.
updateGlobalSize();
}
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
{
setChunkData(name, data, false);
}
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate)
{
if(d->chunks.empty()) {
debug("RIFF::File::setChunkData - No valid chunks found.");
return;
}
if(alwaysCreate && name != "LIST") {
debug("RIFF::File::setChunkData - alwaysCreate should be used for only \"LIST\" chunks.");
return;
}
if(!alwaysCreate) {
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
setChunkData(i, data);
return;
}
}
}
// Couldn't find an existing chunk, so let's create a new one.
// Adjust the padding of the last chunk to place the new chunk at even position.
Chunk &last = d->chunks.back();
long offset = last.offset + last.size + last.padding;
if(offset & 1) {
if(last.padding == 1) {
last.padding = 0; // This should not happen unless the file is corrupted.
offset--;
removeBlock(offset, 1);
}
else {
insert(ByteVector("\0", 1), offset, 0);
last.padding = 1;
offset++;
}
}
// Now add the chunk to the file.
writeChunk(name, data, offset, 0);
// And update our internal structure
Chunk chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 8;
chunk.padding = data.size() % 2;
d->chunks.push_back(chunk);
// Update the global size.
updateGlobalSize();
}
void RIFF::File::removeChunk(unsigned int i)
{
if(i >= d->chunks.size()) {
debug("RIFF::File::removeChunk() - Index out of range.");
return;
}
std::vector<Chunk>::iterator it = d->chunks.begin();
std::advance(it, i);
const unsigned int removeSize = it->size + it->padding + 8;
removeBlock(it->offset - 8, removeSize);
it = d->chunks.erase(it);
for(; it != d->chunks.end(); ++it)
it->offset -= removeSize;
// Update the global size.
updateGlobalSize();
}
void RIFF::File::removeChunk(const ByteVector &name)
{
for(int i = static_cast<int>(d->chunks.size()) - 1; i >= 0; --i) {
if(d->chunks[i].name == name)
removeChunk(i);
}
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void RIFF::File::read()
{
const bool bigEndian = (d->endianness == BigEndian);
long offset = tell();
offset += 4;
d->sizeOffset = offset;
seek(offset);
d->size = readBlock(4).toUInt(bigEndian);
offset += 8;
// + 8: chunk header at least, fix for additional junk bytes
while(offset + 8 <= length()) {
seek(offset);
const ByteVector chunkName = readBlock(4);
const unsigned int chunkSize = readBlock(4).toUInt(bigEndian);
if(!isValidChunkName(chunkName)) {
debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(offset) + 8 + chunkSize > length()) {
debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)");
setValid(false);
break;
}
Chunk chunk;
chunk.name = chunkName;
chunk.size = chunkSize;
chunk.offset = offset + 8;
chunk.padding = 0;
offset = chunk.offset + chunk.size;
// Check padding
if(offset & 1) {
seek(offset);
const ByteVector iByte = readBlock(1);
if(iByte.size() == 1 && iByte[0] == '\0') {
chunk.padding = 1;
offset++;
}
}
d->chunks.push_back(chunk);
}
}
void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long offset, unsigned long replace)
{
ByteVector combined;
combined.append(name);
combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian));
combined.append(data);
if(data.size() & 1)
combined.resize(combined.size() + 1, '\0');
insert(combined, offset, replace);
}
void RIFF::File::updateGlobalSize()
{
const Chunk first = d->chunks.front();
const Chunk last = d->chunks.back();
d->size = last.offset + last.size + last.padding - first.offset + 12;
const ByteVector data = ByteVector::fromUInt(d->size, d->endianness == BigEndian);
insert(data, d->sizeOffset, 4);
}

161
3rdparty/taglib/riff/rifffile.h vendored Normal file
View File

@@ -0,0 +1,161 @@
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_RIFFFILE_H
#define TAGLIB_RIFFFILE_H
#include "taglib_export.h"
#include "tfile.h"
namespace TagLib {
//! An implementation of TagLib::File with RIFF specific methods
namespace RIFF {
//! An RIFF file class with some useful methods specific to RIFF
/*!
* This implements the generic TagLib::File API and additionally provides
* access to properties that are distinct to RIFF files, notably access
* to the different ID3 tags.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* Destroys this instance of the File.
*/
virtual ~File();
protected:
enum Endianness { BigEndian, LittleEndian };
File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness);
/*!
* \return The size of the main RIFF chunk.
*/
unsigned int riffSize() const;
/*!
* \return The number of chunks in the file.
*/
unsigned int chunkCount() const;
/*!
* \return The offset within the file for the selected chunk number.
*/
unsigned int chunkOffset(unsigned int i) const;
/*!
* \return The size of the chunk data.
*/
unsigned int chunkDataSize(unsigned int i) const;
/*!
* \return The size of the padding after the chunk (can be either 0 or 1).
*/
unsigned int chunkPadding(unsigned int i) const;
/*!
* \return The name of the specified chunk, for instance, "COMM" or "ID3 "
*/
ByteVector chunkName(unsigned int i) const;
/*!
* Reads the chunk data from the file and returns it.
*
* \note This \e will move the read pointer for the file.
*/
ByteVector chunkData(unsigned int i);
/*!
* Sets the data for the specified chunk to \a data.
*
* \warning This will update the file immediately.
*/
void setChunkData(unsigned int i, const ByteVector &data);
/*!
* Sets the data for the chunk \a name to \a data. If a chunk with the
* given name already exists it will be overwritten, otherwise it will be
* created after the existing chunks.
*
* \warning This will update the file immediately.
*/
void setChunkData(const ByteVector &name, const ByteVector &data);
/*!
* Sets the data for the chunk \a name to \a data. If a chunk with the
* given name already exists it will be overwritten, otherwise it will be
* created after the existing chunks.
*
* \note If \a alwaysCreate is true, a new chunk is created regardless of
* whether or not the chunk \a name exists. It should only be used for
* "LIST" chunks.
*
* \warning This will update the file immediately.
*/
void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate);
/*!
* Removes the specified chunk.
*
* \warning This will update the file immediately.
*/
void removeChunk(unsigned int i);
/*!
* Removes the chunk \a name.
*
* \warning This will update the file immediately.
* \warning This removes all the chunks with the given name.
*/
void removeChunk(const ByteVector &name);
private:
File(const File &);
File &operator=(const File &);
void read();
void writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long offset, unsigned long replace = 0);
/*!
* Update the global RIFF size based on the current internal structure.
*/
void updateGlobalSize();
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

60
3rdparty/taglib/riff/riffutils.h vendored Normal file
View File

@@ -0,0 +1,60 @@
/***************************************************************************
copyright : (C) 2015 by Tsuda Kageyu
email : tsuda.kageyu@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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_RIFFUTILS_H
#define TAGLIB_RIFFUTILS_H
// THIS FILE IS NOT A PART OF THE TAGLIB API
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
namespace TagLib
{
namespace RIFF
{
namespace
{
inline bool isValidChunkName(const ByteVector &name)
{
if(name.size() != 4)
return false;
for(ByteVector::ConstIterator it = name.begin(); it != name.end(); ++it) {
const int c = static_cast<unsigned char>(*it);
if(c < 32 || 127 < c)
return false;
}
return true;
}
}
}
}
#endif
#endif

256
3rdparty/taglib/riff/wav/infotag.cpp vendored Normal file
View File

@@ -0,0 +1,256 @@
/***************************************************************************
copyright : (C) 2012 by Tsuda Kageyu
email : tsuda.kageyu@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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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/ *
***************************************************************************/
#include <tdebug.h>
#include <tfile.h>
#include "infotag.h"
#include "riffutils.h"
using namespace TagLib;
using namespace RIFF::Info;
namespace
{
const RIFF::Info::StringHandler defaultStringHandler;
const RIFF::Info::StringHandler *stringHandler = &defaultStringHandler;
}
class RIFF::Info::Tag::TagPrivate
{
public:
FieldListMap fieldListMap;
};
////////////////////////////////////////////////////////////////////////////////
// StringHandler implementation
////////////////////////////////////////////////////////////////////////////////
StringHandler::StringHandler()
{
}
StringHandler::~StringHandler()
{
}
String RIFF::Info::StringHandler::parse(const ByteVector &data) const
{
return String(data, String::UTF8);
}
ByteVector RIFF::Info::StringHandler::render(const String &s) const
{
return s.data(String::UTF8);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
RIFF::Info::Tag::Tag(const ByteVector &data) :
TagLib::Tag(),
d(new TagPrivate())
{
parse(data);
}
RIFF::Info::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
}
RIFF::Info::Tag::~Tag()
{
delete d;
}
String RIFF::Info::Tag::title() const
{
return fieldText("INAM");
}
String RIFF::Info::Tag::artist() const
{
return fieldText("IART");
}
String RIFF::Info::Tag::album() const
{
return fieldText("IPRD");
}
String RIFF::Info::Tag::comment() const
{
return fieldText("ICMT");
}
String RIFF::Info::Tag::genre() const
{
return fieldText("IGNR");
}
unsigned int RIFF::Info::Tag::year() const
{
return fieldText("ICRD").substr(0, 4).toInt();
}
unsigned int RIFF::Info::Tag::track() const
{
return fieldText("IPRT").toInt();
}
void RIFF::Info::Tag::setTitle(const String &s)
{
setFieldText("INAM", s);
}
void RIFF::Info::Tag::setArtist(const String &s)
{
setFieldText("IART", s);
}
void RIFF::Info::Tag::setAlbum(const String &s)
{
setFieldText("IPRD", s);
}
void RIFF::Info::Tag::setComment(const String &s)
{
setFieldText("ICMT", s);
}
void RIFF::Info::Tag::setGenre(const String &s)
{
setFieldText("IGNR", s);
}
void RIFF::Info::Tag::setYear(unsigned int i)
{
if(i != 0)
setFieldText("ICRD", String::number(i));
else
d->fieldListMap.erase("ICRD");
}
void RIFF::Info::Tag::setTrack(unsigned int i)
{
if(i != 0)
setFieldText("IPRT", String::number(i));
else
d->fieldListMap.erase("IPRT");
}
bool RIFF::Info::Tag::isEmpty() const
{
return d->fieldListMap.isEmpty();
}
FieldListMap RIFF::Info::Tag::fieldListMap() const
{
return d->fieldListMap;
}
String RIFF::Info::Tag::fieldText(const ByteVector &id) const
{
if(d->fieldListMap.contains(id))
return String(d->fieldListMap[id]);
else
return String();
}
void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s)
{
// id must be four-byte long pure ascii string.
if(!isValidChunkName(id))
return;
if(!s.isEmpty())
d->fieldListMap[id] = s;
else
removeField(id);
}
void RIFF::Info::Tag::removeField(const ByteVector &id)
{
if(d->fieldListMap.contains(id))
d->fieldListMap.erase(id);
}
ByteVector RIFF::Info::Tag::render() const
{
ByteVector data("INFO");
FieldListMap::ConstIterator it = d->fieldListMap.begin();
for(; it != d->fieldListMap.end(); ++it) {
ByteVector text = stringHandler->render(it->second);
if(text.isEmpty())
continue;
data.append(it->first);
data.append(ByteVector::fromUInt(text.size() + 1, false));
data.append(text);
do {
data.append('\0');
} while(data.size() & 1);
}
if(data.size() == 4)
return ByteVector();
else
return data;
}
void RIFF::Info::Tag::setStringHandler(const StringHandler *handler)
{
if(handler)
stringHandler = handler;
else
stringHandler = &defaultStringHandler;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void RIFF::Info::Tag::parse(const ByteVector &data)
{
unsigned int p = 4;
while(p < data.size()) {
const unsigned int size = data.toUInt(p + 4, false);
if(size > data.size() - p - 8)
break;
const ByteVector id = data.mid(p, 4);
if(isValidChunkName(id)) {
const String text = stringHandler->parse(data.mid(p + 8, size));
d->fieldListMap[id] = text;
}
p += ((size + 1) & ~1) + 8;
}
}

192
3rdparty/taglib/riff/wav/infotag.h vendored Normal file
View File

@@ -0,0 +1,192 @@
/***************************************************************************
copyright : (C) 2012 by Tsuda Kageyu
email : tsuda.kageyu@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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_INFOTAG_H
#define TAGLIB_INFOTAG_H
#include "tag.h"
#include "tmap.h"
#include "tstring.h"
#include "tstringlist.h"
#include "tbytevector.h"
#include "taglib_export.h"
namespace TagLib {
class File;
//! A RIFF INFO tag implementation.
namespace RIFF {
namespace Info {
typedef Map<ByteVector, String> FieldListMap;
//! A abstraction for the string to data encoding in Info tags.
/*!
* RIFF INFO tag has no clear definitions about character encodings.
* In practice, local encoding of each system is largely used and UTF-8 is
* popular too.
*
* Here is an option to read and write tags in your preferred encoding
* by subclassing this class, reimplementing parse() and render() and setting
* your reimplementation as the default with Info::Tag::setStringHandler().
*
* \see ID3v1::Tag::setStringHandler()
*/
class TAGLIB_EXPORT StringHandler
{
public:
StringHandler();
~StringHandler();
/*!
* Decode a string from \a data. The default implementation assumes that
* \a data is an UTF-8 character array.
*/
virtual String parse(const ByteVector &data) const;
/*!
* Encode a ByteVector with the data from \a s. The default implementation
* assumes that \a s is an UTF-8 string.
*/
virtual ByteVector render(const String &s) const;
};
//! The main class in the ID3v2 implementation
/*!
* This is the main class in the INFO tag implementation. RIFF INFO tag is a
* metadata format found in WAV audio and AVI video files. Though it is a part
* of Microsoft/IBM's RIFF specification, the author could not find the official
* documents about it. So, this implementation is referring to unofficial documents
* online and some applications' behaviors especially Windows Explorer.
*/
class TAGLIB_EXPORT Tag : public TagLib::Tag
{
public:
/*!
* Constructs an empty INFO tag.
*/
Tag();
/*!
* Constructs an INFO tag read from \a data which is contents of "LIST" chunk.
*/
Tag(const ByteVector &data);
virtual ~Tag();
// Reimplementations
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
virtual bool isEmpty() const;
/*!
* Returns a copy of the internal fields of the tag. The returned map directly
* reflects the contents of the "INFO" chunk.
*
* \note Modifying this map does not affect the tag's internal data.
* Use setFieldText() and removeField() instead.
*
* \see setFieldText()
* \see removeField()
*/
FieldListMap fieldListMap() const;
/*
* Gets the value of the field with the ID \a id.
*/
String fieldText(const ByteVector &id) const;
/*
* Sets the value of the field with the ID \a id to \a s.
* If the field does not exist, it is created.
* If \s is empty, the field is removed.
*
* \note fieldId must be four-byte long pure ASCII string. This function
* performs nothing if fieldId is invalid.
*/
void setFieldText(const ByteVector &id, const String &s);
/*
* Removes the field with the ID \a id.
*/
void removeField(const ByteVector &id);
/*!
* Render the tag back to binary data, suitable to be written to disk.
*
* \note Returns empty ByteVector is the tag contains no fields.
*/
ByteVector render() const;
/*!
* Sets the string handler that decides how the text data will be
* converted to and from binary data.
* If the parameter \a handler is null, the previous handler is
* released and default UTF-8 handler is restored.
*
* \note The caller is responsible for deleting the previous handler
* as needed after it is released.
*
* \see StringHandler
*/
static void setStringHandler(const StringHandler *handler);
protected:
/*!
* Pareses the body of the tag in \a data.
*/
void parse(const ByteVector &data);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}}
}
#endif

257
3rdparty/taglib/riff/wav/wavfile.cpp vendored Normal file
View File

@@ -0,0 +1,257 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "wavfile.h"
#include "id3v2tag.h"
#include "infotag.h"
#include "tagunion.h"
using namespace TagLib;
namespace
{
enum { ID3v2Index = 0, InfoIndex = 1 };
}
class RIFF::WAV::File::FilePrivate
{
public:
FilePrivate() :
properties(0),
hasID3v2(false),
hasInfo(false) {}
~FilePrivate()
{
delete properties;
}
Properties *properties;
TagUnion tag;
bool hasID3v2;
bool hasInfo;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool RIFF::WAV::File::isSupported(IOStream *stream)
{
// A WAV file has to start with "RIFF????WAVE".
const ByteVector id = Utils::readHeader(stream, 12, false);
return (id.startsWith("RIFF") && id.containsAt("WAVE", 8));
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
RIFF::WAV::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
RIFF::File(file, LittleEndian),
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
RIFF::WAV::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
RIFF::File(stream, LittleEndian),
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
RIFF::WAV::File::~File()
{
delete d;
}
ID3v2::Tag *RIFF::WAV::File::tag() const
{
return ID3v2Tag();
}
ID3v2::Tag *RIFF::WAV::File::ID3v2Tag() const
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, false);
}
RIFF::Info::Tag *RIFF::WAV::File::InfoTag() const
{
return d->tag.access<RIFF::Info::Tag>(InfoIndex, false);
}
void RIFF::WAV::File::strip(TagTypes tags)
{
removeTagChunks(tags);
if(tags & ID3v2)
d->tag.set(ID3v2Index, new ID3v2::Tag());
if(tags & Info)
d->tag.set(InfoIndex, new RIFF::Info::Tag());
}
PropertyMap RIFF::WAV::File::properties() const
{
return d->tag.properties();
}
void RIFF::WAV::File::removeUnsupportedProperties(const StringList &unsupported)
{
d->tag.removeUnsupportedProperties(unsupported);
}
PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties)
{
InfoTag()->setProperties(properties);
return ID3v2Tag()->setProperties(properties);
}
RIFF::WAV::Properties *RIFF::WAV::File::audioProperties() const
{
return d->properties;
}
bool RIFF::WAV::File::save()
{
return RIFF::WAV::File::save(AllTags);
}
bool RIFF::WAV::File::save(TagTypes tags, bool stripOthers, int id3v2Version)
{
if(readOnly()) {
debug("RIFF::WAV::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("RIFF::WAV::File::save() -- Trying to save invalid file.");
return false;
}
if(stripOthers)
strip(static_cast<TagTypes>(AllTags & ~tags));
if(tags & ID3v2) {
removeTagChunks(ID3v2);
if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) {
setChunkData("ID3 ", ID3v2Tag()->render(id3v2Version));
d->hasID3v2 = true;
}
}
if(tags & Info) {
removeTagChunks(Info);
if(InfoTag() && !InfoTag()->isEmpty()) {
setChunkData("LIST", InfoTag()->render(), true);
d->hasInfo = true;
}
}
return true;
}
bool RIFF::WAV::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
bool RIFF::WAV::File::hasInfoTag() const
{
return d->hasInfo;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void RIFF::WAV::File::read(bool readProperties)
{
for(unsigned int i = 0; i < chunkCount(); ++i) {
const ByteVector name = chunkName(i);
if(name == "ID3 " || name == "id3 ") {
if(!d->tag[ID3v2Index]) {
d->tag.set(ID3v2Index, new ID3v2::Tag(this, chunkOffset(i)));
d->hasID3v2 = true;
}
else {
debug("RIFF::WAV::File::read() - Duplicate ID3v2 tag found.");
}
}
else if(name == "LIST") {
const ByteVector data = chunkData(i);
if(data.startsWith("INFO")) {
if(!d->tag[InfoIndex]) {
d->tag.set(InfoIndex, new RIFF::Info::Tag(data));
d->hasInfo = true;
}
else {
debug("RIFF::WAV::File::read() - Duplicate INFO tag found.");
}
}
}
}
if(!d->tag[ID3v2Index])
d->tag.set(ID3v2Index, new ID3v2::Tag());
if(!d->tag[InfoIndex])
d->tag.set(InfoIndex, new RIFF::Info::Tag());
if(readProperties)
d->properties = new Properties(this, Properties::Average);
}
void RIFF::WAV::File::removeTagChunks(TagTypes tags)
{
if((tags & ID3v2) && d->hasID3v2) {
removeChunk("ID3 ");
removeChunk("id3 ");
d->hasID3v2 = false;
}
if((tags & Info) && d->hasInfo) {
for(int i = static_cast<int>(chunkCount()) - 1; i >= 0; --i) {
if(chunkName(i) == "LIST" && chunkData(i).startsWith("INFO"))
removeChunk(i);
}
d->hasInfo = false;
}
}

203
3rdparty/taglib/riff/wav/wavfile.h vendored Normal file
View File

@@ -0,0 +1,203 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_WAVFILE_H
#define TAGLIB_WAVFILE_H
#include "rifffile.h"
#include "id3v2tag.h"
#include "infotag.h"
#include "wavproperties.h"
namespace TagLib {
namespace RIFF {
//! An implementation of WAV metadata
/*!
* This is implementation of WAV metadata.
*
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
* chunk as well as properties from the file.
*/
namespace WAV {
//! An implementation of TagLib::File with WAV specific methods
/*!
* This implements and provides an interface for WAV files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to WAV files.
*/
class TAGLIB_EXPORT File : public TagLib::RIFF::File
{
public:
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches ID3v2 tags.
ID3v2 = 0x0001,
//! Matches INFO tags.
Info = 0x0002,
//! Matches all tag types.
AllTags = 0xffff
};
/*!
* Constructs a WAV file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Constructs a WAV file from \a stream. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the ID3v2 Tag for this file.
*
* \note This method does not return all the tags for this file for
* backward compatibility. Will be fixed in TagLib 2.0.
*/
ID3v2::Tag *tag() const;
/*!
* Returns the ID3v2 Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the
* file on disk actually has an ID3v2 tag.
*
* \see hasID3v2Tag()
*/
ID3v2::Tag *ID3v2Tag() const;
/*!
* Returns the RIFF INFO Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has a RIFF INFO tag. Use hasInfoTag() to check if the
* file on disk actually has a RIFF INFO tag.
*
* \see hasInfoTag()
*/
Info::Tag *InfoTag() const;
/*!
* This will strip the tags that match the OR-ed together TagTypes from the
* file. By default it strips all tags. It returns true if the tags are
* successfully stripped.
*
* \note This will update the file immediately.
*/
void strip(TagTypes tags = AllTags);
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the WAV::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
/*!
* Saves the file.
*/
virtual bool save();
bool save(TagTypes tags, bool stripOthers = true, int id3v2Version = 4);
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
/*!
* Returns whether or not the file on disk actually has a RIFF INFO tag.
*
* \see InfoTag()
*/
bool hasInfoTag() const;
/*!
* Returns whether or not the given \a stream can be opened as a WAV
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties);
void removeTagChunks(TagTypes tags);
friend class Properties;
class FilePrivate;
FilePrivate *d;
};
}
}
}
#endif

View File

@@ -0,0 +1,212 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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/ *
***************************************************************************/
#include <tdebug.h>
#include "wavfile.h"
#include "wavproperties.h"
using namespace TagLib;
namespace
{
// Quoted from RFC 2361.
enum WaveFormat
{
FORMAT_UNKNOWN = 0x0000,
FORMAT_PCM = 0x0001
};
}
class RIFF::WAV::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
format(0),
length(0),
bitrate(0),
sampleRate(0),
channels(0),
bitsPerSample(0),
sampleFrames(0) {}
int format;
int length;
int bitrate;
int sampleRate;
int channels;
int bitsPerSample;
unsigned int sampleFrames;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
RIFF::WAV::Properties::Properties(const ByteVector &, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
debug("RIFF::WAV::Properties::Properties() -- This constructor is no longer used.");
}
RIFF::WAV::Properties::Properties(const ByteVector &, unsigned int, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
debug("RIFF::WAV::Properties::Properties() -- This constructor is no longer used.");
}
TagLib::RIFF::WAV::Properties::Properties(File *file, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
read(file);
}
RIFF::WAV::Properties::~Properties()
{
delete d;
}
int RIFF::WAV::Properties::length() const
{
return lengthInSeconds();
}
int RIFF::WAV::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int RIFF::WAV::Properties::lengthInMilliseconds() const
{
return d->length;
}
int RIFF::WAV::Properties::bitrate() const
{
return d->bitrate;
}
int RIFF::WAV::Properties::sampleRate() const
{
return d->sampleRate;
}
int RIFF::WAV::Properties::channels() const
{
return d->channels;
}
int RIFF::WAV::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
int RIFF::WAV::Properties::sampleWidth() const
{
return bitsPerSample();
}
unsigned int RIFF::WAV::Properties::sampleFrames() const
{
return d->sampleFrames;
}
int RIFF::WAV::Properties::format() const
{
return d->format;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void RIFF::WAV::Properties::read(File *file)
{
ByteVector data;
unsigned int streamLength = 0;
unsigned int totalSamples = 0;
for(unsigned int i = 0; i < file->chunkCount(); ++i) {
const ByteVector name = file->chunkName(i);
if(name == "fmt ") {
if(data.isEmpty())
data = file->chunkData(i);
else
debug("RIFF::WAV::Properties::read() - Duplicate 'fmt ' chunk found.");
}
else if(name == "data") {
if(streamLength == 0)
streamLength = file->chunkDataSize(i) + file->chunkPadding(i);
else
debug("RIFF::WAV::Properties::read() - Duplicate 'data' chunk found.");
}
else if(name == "fact") {
if(totalSamples == 0)
totalSamples = file->chunkData(i).toUInt(0, false);
else
debug("RIFF::WAV::Properties::read() - Duplicate 'fact' chunk found.");
}
}
if(data.size() < 16) {
debug("RIFF::WAV::Properties::read() - 'fmt ' chunk not found or too short.");
return;
}
if(streamLength == 0) {
debug("RIFF::WAV::Properties::read() - 'data' chunk not found.");
return;
}
d->format = data.toShort(0, false);
if(d->format != FORMAT_PCM && totalSamples == 0) {
debug("RIFF::WAV::Properties::read() - Non-PCM format, but 'fact' chunk not found.");
return;
}
d->channels = data.toShort(2, false);
d->sampleRate = data.toUInt(4, false);
d->bitsPerSample = data.toShort(14, false);
if(d->format != FORMAT_PCM)
d->sampleFrames = totalSamples;
else if(d->channels > 0 && d->bitsPerSample > 0)
d->sampleFrames = streamLength / (d->channels * ((d->bitsPerSample + 7) / 8));
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
}
else {
const unsigned int byteRate = data.toUInt(8, false);
if(byteRate > 0) {
d->length = static_cast<int>(streamLength * 1000.0 / byteRate + 0.5);
d->bitrate = static_cast<int>(byteRate * 8.0 / 1000.0 + 0.5);
}
}
}

163
3rdparty/taglib/riff/wav/wavproperties.h vendored Normal file
View File

@@ -0,0 +1,163 @@
/***************************************************************************
copyright : (C) 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* 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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 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_WAVPROPERTIES_H
#define TAGLIB_WAVPROPERTIES_H
#include "taglib.h"
#include "audioproperties.h"
namespace TagLib {
class ByteVector;
namespace RIFF {
namespace WAV {
class File;
//! An implementation of audio property reading for WAV
/*!
* This reads the data from an WAV stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
* Create an instance of WAV::Properties with the data read from the
* ByteVector \a data.
*
* \deprecated
*/
Properties(const ByteVector &data, ReadStyle style);
/*!
* Create an instance of WAV::Properties with the data read from the
* ByteVector \a data and the length calculated using \a streamLength.
*
* \deprecated
*/
Properties(const ByteVector &data, unsigned int streamLength, ReadStyle style);
/*!
* Create an instance of WAV::Properties with the data read from the
* WAV::File \a file.
*/
Properties(File *file, ReadStyle style);
/*!
* Destroys this WAV::Properties instance.
*/
virtual ~Properties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns the number of bits per audio sample.
*/
int bitsPerSample() const;
/*!
* Returns the number of bits per audio sample.
*
* \note This method is just an alias of bitsPerSample().
*
* \deprecated
*/
int sampleWidth() const;
/*!
* Returns the number of sample frames.
*/
unsigned int sampleFrames() const;
/*!
* Returns the format ID of the file.
* 0 for unknown, 1 for PCM, 2 for ADPCM, 3 for 32/64-bit IEEE754, and
* so forth.
*
* \note For further information, refer to the WAVE Form Registration
* Numbers in RFC 2361.
*/
int format() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(File *file);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
}
#endif