28 Commits

Author SHA1 Message Date
Lukáš Lalinský
fddf3ed51b Changelog 2012-07-11 12:31:00 +02:00
Jonathan Liu
e2bdbb2cd1 Use the default frame factory when it's necessary to parse ID3v2 tags in APE files
https://bugs.kde.org/show_bug.cgi?id=278773
2012-07-11 12:29:14 +02:00
Lukáš Lalinský
059f2243b3 Prepare 1.7.2 release 2012-04-20 17:57:13 +02:00
Lukáš Lalinský
cce6ad46c9 Reverse the version check, similarly to what mp4v2 does 2012-04-20 17:52:12 +02:00
scottmc
288c6e4a3f Include <iostream> instead of <ostream> to fix compilation on Haiku 2012-03-18 09:20:26 +01:00
Lukáš Lalinský
606edf8171 Increment the version number 2012-03-17 11:02:24 +01:00
Lukáš Lalinský
009c43952f Changelog 2012-03-17 10:58:22 +01:00
Birunthan Mohnathas
9c1668f28b Fixed (huge) memory leak with ASF. 2012-03-17 10:48:57 +01:00
Lukáš Lalinský
110cac8429 Avoid uint overflow in case the length + index is over UINT_MAX 2012-03-10 09:13:04 +01:00
Lukáš Lalinský
258ae751b5 Don't store the output of ByteVector::toUInt() in int, use uint instead 2012-03-10 09:12:32 +01:00
Lukáš Lalinský
df1d3e028e Make sure to not try dividing by zero 2012-03-10 09:12:19 +01:00
Stephen F. Booth
23c86cf27d Check if the header is TTA1 before parsing 2012-03-10 09:11:51 +01:00
Lukáš Lalinský
f59c3b67aa Detect RIFF files with invalid chunk sizes
The bug report has a WAVE file with zero-sized 'data' chunk, which causes
TagLib to iterate over the file, 8 bytes in each iteration. The new code
adds a check for the chunk name, which forces it to mark the file as
invalid if the chunk name doesn't contain ASCII characters.

https://bugs.kde.org/show_bug.cgi?id=283412
2012-03-10 09:06:55 +01:00
Stephen F. Booth
294cb22241 Don't crash when wav files have a 0 for bit per channel (sampleWidth)
I've seen this in a wav that has an audio format of MP3 (0x55)
2012-03-10 08:58:45 +01:00
Frank Lai
b7ec0d26ab Be more careful when parsing Vorbis Comments 2012-03-10 08:52:59 +01:00
Scott Wheeler
934ce51790 Don't lead the scanned blocks on save 2012-03-10 08:52:17 +01:00
Modestas Vainius
d112a68193 Support building documentation out-of-source-dir 2011-04-09 19:15:46 +02:00
Lukáš Lalinský
f624d6e2af Don't overwrite fields that already exist
We can have multiple fields in the Vorbis Comment (e.g. two artist names),
but TagUnion only takes the first one, so it will effectively strip the
extra fields.

https://bugs.kde.org/show_bug.cgi?id=268854
2011-03-19 07:42:47 +01:00
Lukáš Lalinský
d3e79ddc38 Partial protection against broken WMA files
This fixes the problem on the reported file, but in general this code
needs a lot more checks.

https://bugs.kde.org/show_bug.cgi?id=268401
2011-03-19 07:42:23 +01:00
Lukáš Lalinský
b3ae839a38 Add release date 2011-03-11 14:15:38 +01:00
Lukáš Lalinský
cce88b7005 News for 1.7 2011-03-11 13:21:54 +01:00
Lukáš Lalinský
311be56432 Merge commit 'eee860f9c6' into release-1.7 2011-03-11 13:19:35 +01:00
Lukáš Lalinský
5685dd078f Fix memory leaks in the FLAC parsing code
Thanks to Daniel Schaack for reporting these.
2011-03-11 10:29:27 +01:00
Raphael Kubo da Costa
eee860f9c6 Fix build when the 'uint' typedef is already defined.
Using uint in those structs gave me the following error:

  /home/rakuco/kde4/src/kdesupport/taglib/taglib/riff/rifffile.cpp:38:
error: reference to 'uint' is ambiguous
  /usr/include/sys/types.h:56: error: candidates are: typedef unsigned
int uint

Is it really necessary to have those typedefs in taglib.h? It'd be
nice to at least check if they are not being redefined.

CCMAIL: lalinsky@gmail.com



git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1223282 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
2011-03-02 03:05:28 +00:00
Lukáš Lalinský
10fff6d797 Update the AIFF test
git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1222753 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
2011-02-25 19:43:25 +00:00
Lukáš Lalinský
7cc1ce1c36 Fix the patch from r1222376
git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1222752 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
2011-02-25 19:42:49 +00:00
Nick Shaforostoff
272719e666 a formal change: convert rifffile.cpp to use vector of structs instead of several vectors of simple types
git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1222376 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
2011-02-23 09:16:25 +00:00
Nick Shaforostoff
d21ff8be54 divide by 1000 instead of 1024 when calculating riff bitrate to get standard 1411 kbps bitrate on AudioCD wavs
CCMAIL:taglib-devel@kde.org



git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1222375 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
2011-02-23 08:58:17 +00:00
27 changed files with 287 additions and 99 deletions

View File

@@ -40,7 +40,7 @@ endif (WIN32)
SET(TAGLIB_LIB_MAJOR_VERSION "1")
SET(TAGLIB_LIB_MINOR_VERSION "7")
SET(TAGLIB_LIB_PATCH_VERSION "0")
SET(TAGLIB_LIB_PATCH_VERSION "2")
SET(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}")
@@ -76,6 +76,7 @@ endif(NOT WIN32)
INSTALL( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/taglib-config DESTINATION ${BIN_INSTALL_DIR})
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
file(COPY doc/taglib.png DESTINATION doc)
ADD_CUSTOM_TARGET(docs doxygen)

View File

@@ -61,7 +61,7 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = taglib
INPUT = @CMAKE_SOURCE_DIR@/taglib
FILE_PATTERNS = *.h \
*.hh \
*.H
@@ -96,9 +96,9 @@ IGNORE_PREFIX =
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER = doc/api-header.html
HTML_FOOTER = doc/api-footer.html
HTML_STYLESHEET = doc/taglib-api.css
HTML_HEADER = @CMAKE_SOURCE_DIR@/doc/api-header.html
HTML_FOOTER = @CMAKE_SOURCE_DIR@/doc/api-footer.html
HTML_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/taglib-api.css
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =

30
NEWS
View File

@@ -1,5 +1,31 @@
TagLib 1.7
==========
TagLib 1.7.3 (Jul 12, 2012)
===========================
* Fixed crash when parsing ID3v2 tags from APE files (BUG:278773).
TagLib 1.7.2 (Apr 20, 2012)
===========================
* Fixed division by zero while parsing corrupted MP4 files (CVE-2012-2396).
* Fixed compilation on Haiku.
TagLib 1.7.1 (Mar 17, 2012)
===========================
* Improved parsing of corrupted WMA, RIFF and OGG files.
* Fixed a memory leak in the WMA parser.
* Fixed a memory leak in the FLAC parser.
* Fixed a possible division by zero in the APE parser.
* Added detection of TTA2 files.
* Fixed saving of multiple identically named tags to Vorbis Comments.
TagLib 1.7 (Mar 11, 2011)
=========================
1.7:
* Fixed memory leaks in the FLAC file format parser.
* Fixed bitrate calculation for WAV files.
1.7 RC1:

View File

@@ -24,7 +24,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <ostream>
#include <iostream>
#include <bitset>
#include <tstring.h>

View File

@@ -137,7 +137,7 @@ long APE::Properties::findDescriptor()
long ID3v2OriginalSize = 0;
bool hasID3v2 = false;
if(ID3v2Location >= 0) {
ID3v2::Tag tag(d->file, ID3v2Location, 0);
ID3v2::Tag tag(d->file, ID3v2Location);
ID3v2OriginalSize = tag.header()->completeTagSize();
if(tag.header()->tagSize() > 0)
hasID3v2 = true;
@@ -193,7 +193,7 @@ void APE::Properties::analyzeCurrent()
uint blocksPerFrame = header.mid(4, 4).toUInt(false);
uint finalFrameBlocks = header.mid(8, 4).toUInt(false);
uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0;
d->length = totalBlocks / d->sampleRate;
d->length = d->sampleRate > 0 ? totalBlocks / d->sampleRate : 0;
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
}

View File

@@ -141,11 +141,19 @@ class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
{
public:
List<ASF::File::BaseObject *> objects;
~HeaderExtensionObject();
ByteVector guid();
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
ASF::File::HeaderExtensionObject::~HeaderExtensionObject()
{
for(unsigned int i = 0; i < objects.size(); i++) {
delete objects[i];
}
}
void ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
{
data.clear();
@@ -319,7 +327,16 @@ void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
long long dataPos = 0;
while(dataPos < dataSize) {
ByteVector guid = file->readBlock(16);
long long size = file->readQWORD();
if(guid.size() != 16) {
file->setValid(false);
break;
}
bool ok;
long long size = file->readQWORD(&ok);
if(!ok) {
file->setValid(false);
break;
}
BaseObject *obj;
if(guid == metadataGuid) {
obj = new MetadataObject();
@@ -389,19 +406,37 @@ void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*properties
ByteVector guid = readBlock(16);
if(guid != headerGuid) {
debug("ASF: Not an ASF file.");
setValid(false);
return;
}
d->tag = new ASF::Tag();
d->properties = new ASF::Properties();
d->size = readQWORD();
int numObjects = readDWORD();
bool ok;
d->size = readQWORD(&ok);
if(!ok) {
setValid(false);
return;
}
int numObjects = readDWORD(&ok);
if(!ok) {
setValid(false);
return;
}
seek(2, Current);
for(int i = 0; i < numObjects; i++) {
ByteVector guid = readBlock(16);
long size = (long)readQWORD();
if(guid.size() != 16) {
setValid(false);
break;
}
long size = (long)readQWORD(&ok);
if(!ok) {
setValid(false);
break;
}
BaseObject *obj;
if(guid == filePropertiesGuid) {
obj = new FilePropertiesObject();
@@ -429,7 +464,12 @@ void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*properties
bool ASF::File::save()
{
if(readOnly()) {
debug("ASF: File is read-only.");
debug("ASF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("ASF::File::save() -- Trying to save invalid file.");
return false;
}
@@ -491,27 +531,47 @@ bool ASF::File::save()
// protected members
////////////////////////////////////////////////////////////////////////////////
int ASF::File::readBYTE()
int ASF::File::readBYTE(bool *ok)
{
ByteVector v = readBlock(1);
if(v.size() != 1) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v[0];
}
int ASF::File::readWORD()
int ASF::File::readWORD(bool *ok)
{
ByteVector v = readBlock(2);
if(v.size() != 2) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v.toUShort(false);
}
unsigned int ASF::File::readDWORD()
unsigned int ASF::File::readDWORD(bool *ok)
{
ByteVector v = readBlock(4);
if(v.size() != 4) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v.toUInt(false);
}
long long ASF::File::readQWORD()
long long ASF::File::readQWORD(bool *ok)
{
ByteVector v = readBlock(8);
if(v.size() != 8) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v.toLongLong(false);
}

View File

@@ -88,10 +88,10 @@ namespace TagLib {
private:
int readBYTE();
int readWORD();
unsigned int readDWORD();
long long readQWORD();
int readBYTE(bool *ok = 0);
int readWORD(bool *ok = 0);
unsigned int readDWORD(bool *ok = 0);
long long readQWORD(bool *ok = 0);
static ByteVector renderString(const String &str, bool includeLength = false);
String readString(int len);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);

View File

@@ -65,13 +65,13 @@ public:
hasID3v2(false),
hasID3v1(false)
{
for(uint i = 0; i < blocks.size(); i++) {
delete blocks[i];
}
}
~FilePrivate()
{
for(uint i = 0; i < blocks.size(); i++) {
delete blocks[i];
}
delete properties;
}
@@ -149,7 +149,7 @@ bool FLAC::File::save()
// Create new vorbis comments
Tag::duplicate(&d->tag, xiphComment(true), true);
Tag::duplicate(&d->tag, xiphComment(true), false);
d->xiphCommentData = xiphComment()->render(false);
@@ -161,10 +161,12 @@ bool FLAC::File::save()
MetadataBlock *block = d->blocks[i];
if(block->code() == MetadataBlock::VorbisComment) {
// Set the new Vorbis Comment block
delete block;
block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData);
foundVorbisCommentBlock = true;
}
if(block->code() == MetadataBlock::Padding) {
delete block;
continue;
}
newBlocks.append(block);
@@ -190,7 +192,7 @@ bool FLAC::File::save()
// Adjust the padding block(s)
long originalLength = d->streamStart - d->flacStart;
int paddingLength = originalLength - data.size() - 4;
int paddingLength = originalLength - data.size() - 4;
if (paddingLength < 0) {
paddingLength = MinPaddingLength;
}
@@ -403,6 +405,7 @@ void FLAC::File::scan()
}
else {
debug("FLAC::File::scan() -- invalid picture found, discarting");
delete picture;
}
}
@@ -412,6 +415,9 @@ void FLAC::File::scan()
if(block->code() != MetadataBlock::Padding) {
d->blocks.append(block);
}
else {
delete block;
}
nextBlockOffset += length + 4;

View File

@@ -91,15 +91,24 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
file->seek(mdhd->offset);
data = file->readBlock(mdhd->length);
if(data[8] == 0) {
unsigned int unit = data.mid(20, 4).toUInt();
unsigned int length = data.mid(24, 4).toUInt();
d->length = length / unit;
}
else {
uint version = data[8];
if(version == 1) {
if (data.size() < 36 + 8) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
long long unit = data.mid(28, 8).toLongLong();
long long length = data.mid(36, 8).toLongLong();
d->length = int(length / unit);
d->length = unit ? int(length / unit) : 0;
}
else {
if (data.size() < 24 + 4) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unsigned int unit = data.mid(20, 4).toUInt();
unsigned int length = data.mid(24, 4).toUInt();
d->length = unit ? length / unit : 0;
}
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");

View File

@@ -23,7 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <ostream>
#include <iostream>
#include <bitset>
#include <tstring.h>

View File

@@ -23,7 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <ostream>
#include <iostream>
#include "id3v2synchdata.h"

View File

@@ -287,7 +287,7 @@ void Ogg::XiphComment::parse(const ByteVector &data)
int pos = 0;
int vendorLength = data.mid(0, 4).toUInt(false);
uint vendorLength = data.mid(0, 4).toUInt(false);
pos += 4;
d->vendorID = String(data.mid(pos, vendorLength), String::UTF8);
@@ -295,21 +295,31 @@ void Ogg::XiphComment::parse(const ByteVector &data)
// Next the number of fields in the comment vector.
int commentFields = data.mid(pos, 4).toUInt(false);
uint commentFields = data.mid(pos, 4).toUInt(false);
pos += 4;
for(int i = 0; i < commentFields; i++) {
if(commentFields > (data.size() - 8) / 4) {
return;
}
for(uint i = 0; i < commentFields; i++) {
// Each comment field is in the format "KEY=value" in a UTF8 string and has
// 4 bytes before the text starts that gives the length.
int commentLength = data.mid(pos, 4).toUInt(false);
uint commentLength = data.mid(pos, 4).toUInt(false);
pos += 4;
String comment = String(data.mid(pos, commentLength), String::UTF8);
pos += commentLength;
if(pos > data.size()) {
break;
}
int commentSeparatorPosition = comment.find("=");
if(commentSeparatorPosition == -1) {
break;
}
String key = comment.substr(0, commentSeparatorPosition);
String value = comment.substr(commentSeparatorPosition + 1);

View File

@@ -87,6 +87,11 @@ bool RIFF::AIFF::File::save()
return false;
}
if(!isValid()) {
debug("RIFF::AIFF::File::save() -- Trying to save invalid file.");
return false;
}
setChunkData(d->tagChunkID, d->tag->render());
return true;

View File

@@ -148,6 +148,6 @@ void RIFF::AIFF::Properties::read(const ByteVector &data)
d->sampleWidth = data.mid(6, 2).toShort();
double sampleRate = ConvertFromIeeeExtended(reinterpret_cast<unsigned char *>(data.mid(8, 10).data()));
d->sampleRate = sampleRate;
d->bitrate = (sampleRate * d->sampleWidth * d->channels) / 1024.0;
d->length = sampleFrames / d->sampleRate;
d->bitrate = (sampleRate * d->sampleWidth * d->channels) / 1000.0;
d->length = d->sampleRate > 0 ? sampleFrames / d->sampleRate : 0;
}

View File

@@ -32,6 +32,14 @@
using namespace TagLib;
struct Chunk
{
ByteVector name;
TagLib::uint offset;
TagLib::uint size;
char padding;
};
class RIFF::File::FilePrivate
{
public:
@@ -43,13 +51,10 @@ public:
}
Endianness endianness;
ByteVector type;
uint size;
TagLib::uint size;
ByteVector format;
std::vector<ByteVector> chunkNames;
std::vector<uint> chunkOffsets;
std::vector<uint> chunkSizes;
std::vector<char> chunkPadding;
std::vector<Chunk> chunks;
};
////////////////////////////////////////////////////////////////////////////////
@@ -81,22 +86,22 @@ TagLib::uint RIFF::File::riffSize() const
TagLib::uint RIFF::File::chunkCount() const
{
return d->chunkNames.size();
return d->chunks.size();
}
TagLib::uint RIFF::File::chunkDataSize(uint i) const
{
return d->chunkSizes[i];
return d->chunks[i].size;
}
TagLib::uint RIFF::File::chunkOffset(uint i) const
{
return d->chunkOffsets[i];
return d->chunks[i].offset;
}
TagLib::uint RIFF::File::chunkPadding(uint i) const
{
return d->chunkPadding[i];
return d->chunks[i].padding;
}
ByteVector RIFF::File::chunkName(uint i) const
@@ -104,7 +109,7 @@ ByteVector RIFF::File::chunkName(uint i) const
if(i >= chunkCount())
return ByteVector::null;
return d->chunkNames[i];
return d->chunks[i].name;
}
ByteVector RIFF::File::chunkData(uint i)
@@ -117,39 +122,39 @@ ByteVector RIFF::File::chunkData(uint i)
long begin = 12 + 8;
for(uint it = 0; it < i; it++)
begin += 8 + d->chunkSizes[it] + d->chunkPadding[it];
begin += 8 + d->chunks[it].size + d->chunks[it].padding;
seek(begin);
return readBlock(d->chunkSizes[i]);
return readBlock(d->chunks[i].size);
}
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
{
if(d->chunkNames.size() == 0) {
if(d->chunks.size() == 0) {
debug("RIFF::File::setChunkData - No valid chunks found.");
return;
}
for(uint i = 0; i < d->chunkNames.size(); i++) {
if(d->chunkNames[i] == name) {
for(uint i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (d->chunkSizes[i] + d->chunkPadding[i]);
d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding);
insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4);
// Now update the specific chunk
writeChunk(name, data, d->chunkOffsets[i] - 8, d->chunkSizes[i] + d->chunkPadding[i] + 8);
writeChunk(name, data, d->chunks[i].offset - 8, d->chunks[i].size + d->chunks[i].padding + 8);
d->chunkSizes[i] = data.size();
d->chunkPadding[i] = (data.size() & 0x01) ? 1 : 0;
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
for(i++; i < d->chunkNames.size(); i++)
d->chunkOffsets[i] = d->chunkOffsets[i-1] + 8 + d->chunkSizes[i-1] + d->chunkPadding[i-1];
for(i++; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding;
return;
}
@@ -157,8 +162,8 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
// Couldn't find an existing chunk, so let's create a new one.
uint i = d->chunkNames.size() - 1;
ulong offset = d->chunkOffsets[i] + d->chunkSizes[i];
uint i = d->chunks.size() - 1;
ulong offset = d->chunks[i].offset + d->chunks[i].size;
// First we update the global size
@@ -172,19 +177,36 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
// And update our internal structure
if (offset & 1) {
d->chunkPadding[i] = 1;
d->chunks[i].padding = 1;
offset++;
}
d->chunkNames.push_back(name);
d->chunkSizes.push_back(data.size());
d->chunkOffsets.push_back(offset + 8);
d->chunkPadding.push_back((data.size() & 0x01) ? 1 : 0);
Chunk chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 8;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
d->chunks.push_back(chunk);
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
static bool isValidChunkID(const ByteVector &name)
{
if(name.size() != 4) {
return false;
}
for(int i = 0; i < 4; i++) {
if(name[i] < 32 || name[i] > 127) {
return false;
}
}
return true;
}
void RIFF::File::read()
{
bool bigEndian = (d->endianness == BigEndian);
@@ -198,20 +220,27 @@ void RIFF::File::read()
ByteVector chunkName = readBlock(4);
uint chunkSize = readBlock(4).toUInt(bigEndian);
if(tell() + chunkSize > uint(length())) {
// something wrong
if(!isValidChunkID(chunkName)) {
debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
setValid(false);
break;
}
d->chunkNames.push_back(chunkName);
d->chunkSizes.push_back(chunkSize);
if(tell() + chunkSize > uint(length())) {
debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)");
setValid(false);
break;
}
d->chunkOffsets.push_back(tell());
Chunk chunk;
chunk.name = chunkName;
chunk.size = chunkSize;
chunk.offset = tell();
seek(chunkSize, Current);
seek(chunk.size, Current);
// check padding
char paddingSize = 0;
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
@@ -220,10 +249,10 @@ void RIFF::File::read()
seek(uPosNotPadded, Beginning);
}
else {
paddingSize = 1;
chunk.padding = 1;
}
}
d->chunkPadding.push_back(paddingSize);
d->chunks.push_back(chunk);
}
}

View File

@@ -87,6 +87,11 @@ bool RIFF::WAV::File::save()
return false;
}
if(!isValid()) {
debug("RIFF::WAV::File::save() -- Trying to save invalid file.");
return false;
}
setChunkData(d->tagChunkID, d->tag->render());
return true;

View File

@@ -114,7 +114,7 @@ void RIFF::WAV::Properties::read(const ByteVector &data)
d->sampleWidth = data.mid(14, 2).toShort(false);
uint byteRate = data.mid(8, 4).toUInt(false);
d->bitrate = byteRate * 8 / 1024;
d->bitrate = byteRate * 8 / 1000;
d->length = byteRate > 0 ? d->streamLength / byteRate : 0;
}

View File

@@ -23,7 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <ostream>
#include <iostream>
#include <tstring.h>
#include <tdebug.h>
@@ -363,7 +363,7 @@ ByteVector ByteVector::mid(uint index, uint length) const
ConstIterator endIt;
if(length < 0xffffffff && length + index < size())
if(length < size() - index)
endIt = d->data.begin() + index + length;
else
endIt = d->data.end();

View File

@@ -30,7 +30,7 @@
#include "taglib_export.h"
#include <vector>
#include <ostream>
#include <iostream>
namespace TagLib {

View File

@@ -27,7 +27,7 @@
#include "unicode.h"
#include "tdebug.h"
#include <ostream>
#include <iostream>
#include <string.h>

View File

@@ -31,7 +31,7 @@
#include "tbytevector.h"
#include <string>
#include <ostream>
#include <iostream>
/*!
* \relates TagLib::String

View File

@@ -31,7 +31,7 @@
#include "tbytevectorlist.h"
#include "taglib_export.h"
#include <ostream>
#include <iostream>
namespace TagLib {

View File

@@ -118,19 +118,26 @@ void TrueAudio::Properties::read()
int pos = 3;
d->version = d->data[pos] - '0';
pos += 1 + 2;
pos += 1;
d->channels = d->data.mid(pos, 2).toShort(false);
pos += 2;
// According to http://en.true-audio.com/TTA_Lossless_Audio_Codec_-_Format_Description
// TTA2 headers are in development, and have a different format
if(1 == d->version) {
// Skip the audio format
pos += 2;
d->bitsPerSample = d->data.mid(pos, 2).toShort(false);
pos += 2;
d->channels = d->data.mid(pos, 2).toShort(false);
pos += 2;
d->sampleRate = d->data.mid(pos, 4).toUInt(false);
pos += 4;
d->bitsPerSample = d->data.mid(pos, 2).toShort(false);
pos += 2;
unsigned long samples = d->data.mid(pos, 4).toUInt(false);
d->length = samples / d->sampleRate;
d->sampleRate = d->data.mid(pos, 4).toUInt(false);
pos += 4;
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
uint sampleFrames = d->data.mid(pos, 4).toUInt(false);
d->length = d->sampleRate > 0 ? sampleFrames / d->sampleRate : 0;
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
}
}

Binary file not shown.

View File

@@ -23,7 +23,7 @@ public:
string filename = copy.fileName();
RIFF::AIFF::File *f = new RIFF::AIFF::File(filename.c_str());
CPPUNIT_ASSERT_EQUAL(689, f->audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(705, f->audioProperties()->bitrate());
}
};

View File

@@ -5,6 +5,7 @@
#include <tstringlist.h>
#include <tbytevectorlist.h>
#include <flacfile.h>
#include <xiphcomment.h>
#include "utils.h"
using namespace std;
@@ -20,6 +21,7 @@ class TestFLAC : public CppUnit::TestFixture
CPPUNIT_TEST(testReplacePicture);
CPPUNIT_TEST(testRemoveAllPictures);
CPPUNIT_TEST(testRepeatedSave);
CPPUNIT_TEST(testSaveMultipleValues);
CPPUNIT_TEST_SUITE_END();
public:
@@ -186,6 +188,26 @@ public:
CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title());
}
void testSaveMultipleValues()
{
ScopedFileCopy copy("silence-44-s", ".flac", false);
string newname = copy.fileName();
FLAC::File *f = new FLAC::File(newname.c_str());
Ogg::XiphComment* c = f->xiphComment(true);
c->addField("ARTIST", "artist 1", true);
c->addField("ARTIST", "artist 2", false);
f->save();
delete f;
f = new FLAC::File(newname.c_str());
c = f->xiphComment(true);
Ogg::FieldListMap m = c->fieldListMap();
CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), m["ARTIST"].size());
CPPUNIT_ASSERT_EQUAL(String("artist 1"), m["ARTIST"][0]);
CPPUNIT_ASSERT_EQUAL(String("artist 2"), m["ARTIST"][1]);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC);

View File

@@ -13,6 +13,7 @@ class TestWAV : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestWAV);
CPPUNIT_TEST(testLength);
CPPUNIT_TEST(testZeroSizeDataChunk);
CPPUNIT_TEST_SUITE_END();
public:
@@ -20,9 +21,16 @@ public:
void testLength()
{
RIFF::WAV::File f("data/empty.wav");
CPPUNIT_ASSERT_EQUAL(true, f.isValid());
CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
}
void testZeroSizeDataChunk()
{
RIFF::WAV::File f("data/zero-size-chunk.wav");
CPPUNIT_ASSERT_EQUAL(false, f.isValid());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV);