From 1f7715a5da82f79e17bd69d3d71af9751a7f32be Mon Sep 17 00:00:00 2001 From: Steve Lhomme Date: Tue, 15 Sep 2015 13:15:29 +0200 Subject: [PATCH 01/15] Add support for M4V tag parsing --- taglib/fileref.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 2b5d5f23..7914996c 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -155,6 +155,7 @@ StringList FileRef::defaultFileExtensions() l.append("m4p"); l.append("3g2"); l.append("mp4"); + l.append("m4v"); l.append("wma"); l.append("asf"); l.append("aif"); @@ -261,7 +262,7 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "TTA") return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") + if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V") return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WMA" || ext == "ASF") return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); From b541ec8b682d51f5640ac33f6de2d33cb600bb80 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 12:35:29 +0900 Subject: [PATCH 02/15] Remove some private data members not needed to be carried. --- taglib/mpeg/id3v1/id3v1tag.cpp | 30 ++++++++++++++---------------- taglib/mpeg/id3v1/id3v1tag.h | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/taglib/mpeg/id3v1/id3v1tag.cpp b/taglib/mpeg/id3v1/id3v1tag.cpp index f4004184..4a7d50d6 100644 --- a/taglib/mpeg/id3v1/id3v1tag.cpp +++ b/taglib/mpeg/id3v1/id3v1tag.cpp @@ -35,10 +35,9 @@ using namespace ID3v1; class ID3v1::Tag::TagPrivate { public: - TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {} - - File *file; - long tagOffset; + TagPrivate() : + track(0), + genre(255) {} String title; String artist; @@ -81,18 +80,17 @@ ByteVector ID3v1::StringHandler::render(const String &s) const // public methods //////////////////////////////////////////////////////////////////////////////// -ID3v1::Tag::Tag() : TagLib::Tag() +ID3v1::Tag::Tag() : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; } -ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag() +ID3v1::Tag::Tag(File *file, long tagOffset) : + TagLib::Tag(), + d(new TagPrivate()) { - d = new TagPrivate; - d->file = file; - d->tagOffset = tagOffset; - - read(); + read(file, tagOffset); } ID3v1::Tag::~Tag() @@ -214,12 +212,12 @@ void ID3v1::Tag::setStringHandler(const StringHandler *handler) // protected methods //////////////////////////////////////////////////////////////////////////////// -void ID3v1::Tag::read() +void ID3v1::Tag::read(File *file, long tagOffset) { - if(d->file && d->file->isValid()) { - d->file->seek(d->tagOffset); + if(file && file->isValid()) { + file->seek(tagOffset); // read the tag -- always 128 bytes - ByteVector data = d->file->readBlock(128); + const ByteVector data = file->readBlock(128); // some initial sanity checking if(data.size() == 128 && data.startsWith("TAG")) diff --git a/taglib/mpeg/id3v1/id3v1tag.h b/taglib/mpeg/id3v1/id3v1tag.h index 4cba00db..02642ca5 100644 --- a/taglib/mpeg/id3v1/id3v1tag.h +++ b/taglib/mpeg/id3v1/id3v1tag.h @@ -183,7 +183,7 @@ namespace TagLib { /*! * Reads from the file specified in the constructor. */ - void read(); + void read(File *file, long tagOffset); /*! * Pareses the body of the tag in \a data. */ From 5e37f0101de147b8bf35611cdd5e085e1d576718 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 12:53:52 +0900 Subject: [PATCH 03/15] Remove some private data members not needed to be carried. --- taglib/ape/apetag.cpp | 27 ++++++++------------------- taglib/ape/apetag.h | 2 +- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/taglib/ape/apetag.cpp b/taglib/ape/apetag.cpp index 170a77c8..71a98c18 100644 --- a/taglib/ape/apetag.cpp +++ b/taglib/ape/apetag.cpp @@ -46,15 +46,7 @@ using namespace APE; class APE::Tag::TagPrivate { public: - TagPrivate() : - file(0), - footerLocation(-1) {} - - TagLib::File *file; - long footerLocation; - Footer footer; - ItemListMap itemListMap; }; @@ -72,10 +64,7 @@ APE::Tag::Tag(TagLib::File *file, long footerLocation) : TagLib::Tag(), d(new TagPrivate()) { - d->file = file; - d->footerLocation = footerLocation; - - read(); + read(file, footerLocation); } APE::Tag::~Tag() @@ -330,19 +319,19 @@ bool APE::Tag::isEmpty() const // protected methods //////////////////////////////////////////////////////////////////////////////// -void APE::Tag::read() +void APE::Tag::read(TagLib::File *file, long footerLocation) { - if(d->file && d->file->isValid()) { + if(file && file->isValid()) { - d->file->seek(d->footerLocation); - d->footer.setData(d->file->readBlock(Footer::size())); + file->seek(footerLocation); + d->footer.setData(file->readBlock(Footer::size())); if(d->footer.tagSize() <= Footer::size() || - d->footer.tagSize() > uint(d->file->length())) + d->footer.tagSize() > uint(file->length())) return; - d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize()); - parse(d->file->readBlock(d->footer.tagSize() - Footer::size())); + file->seek(footerLocation + Footer::size() - d->footer.tagSize()); + parse(file->readBlock(d->footer.tagSize() - Footer::size())); } } diff --git a/taglib/ape/apetag.h b/taglib/ape/apetag.h index 55572612..6c9999cf 100644 --- a/taglib/ape/apetag.h +++ b/taglib/ape/apetag.h @@ -188,7 +188,7 @@ namespace TagLib { /*! * Reads from the file specified in the constructor. */ - void read(); + void read(TagLib::File *file, long footerLocation); /*! * Parses the body of the tag in \a data. From f1b683b5829e00adc91266a1846bd1910c49d7bd Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 13:09:11 +0900 Subject: [PATCH 04/15] Remove some private data members not needed to be carried. --- taglib/mpeg/id3v2/id3v2tag.cpp | 36 ++++++++++++++++++---------------- taglib/mpeg/id3v2/id3v2tag.h | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index be5bfd20..636d9eb2 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -55,8 +55,7 @@ class ID3v2::Tag::TagPrivate { public: TagPrivate() : - file(0), - tagOffset(-1), + fileLength(0), extendedHeader(0), footer(0) { @@ -69,8 +68,7 @@ public: delete footer; } - File *file; - long tagOffset; + long fileLength; const FrameFactory *factory; Header header; @@ -124,11 +122,9 @@ ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) : TagLib::Tag(), d(new TagPrivate()) { - d->file = file; - d->tagOffset = tagOffset; d->factory = factory; - read(); + read(file, tagOffset); } ID3v2::Tag::~Tag() @@ -617,7 +613,8 @@ ByteVector ID3v2::Tag::render(int version) const // Compute the amount of padding, and append that to tagData. // TODO: Should be calculated in offset_t in taglib2. - long paddingSize = d->header.tagSize() - (tagData.size() - Header::size()); + long originalSize = d->header.tagSize(); + long paddingSize = originalSize - (tagData.size() - Header::size()); if(paddingSize <= 0) { paddingSize = MinPaddingSize; @@ -625,7 +622,7 @@ ByteVector ID3v2::Tag::render(int version) const else { // Padding won't increase beyond 1% of the file size or 1MB. - long threshold = d->file ? d->file->length() / 100 : 0; + long threshold = d->fileLength / 100; threshold = std::max(threshold, MinPaddingSize); threshold = std::min(threshold, MaxPaddingSize); @@ -639,6 +636,9 @@ ByteVector ID3v2::Tag::render(int version) const d->header.setMajorVersion(version); d->header.setTagSize(tagData.size() - Header::size()); + if(d->fileLength > 0) + d->fileLength += (d->header.tagSize() - originalSize); + // TODO: This should eventually include d->footer->render(). const ByteVector headerData = d->header.render(); std::copy(headerData.begin(), headerData.end(), tagData.begin()); @@ -663,22 +663,24 @@ void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler) // protected members //////////////////////////////////////////////////////////////////////////////// -void ID3v2::Tag::read() +void ID3v2::Tag::read(TagLib::File *file, long offset) { - if(!d->file) + if(!file) return; - if(!d->file->isOpen()) + if(!file->isOpen()) return; - d->file->seek(d->tagOffset); - d->header.setData(d->file->readBlock(Header::size())); + d->fileLength = file->length(); + + file->seek(offset); + d->header.setData(file->readBlock(Header::size())); // If the tag size is 0, then this is an invalid tag (tags must contain at // least one frame) if(d->header.tagSize() != 0) - parse(d->file->readBlock(d->header.tagSize())); + parse(file->readBlock(d->header.tagSize())); // Look for duplicate ID3v2 tags and treat them as an extra blank of this one. // It leads to overwriting them with zero when saving the tag. @@ -690,9 +692,9 @@ void ID3v2::Tag::read() while(true) { - d->file->seek(d->tagOffset + d->header.completeTagSize() + extraSize); + file->seek(offset + d->header.completeTagSize() + extraSize); - const ByteVector data = d->file->readBlock(Header::size()); + const ByteVector data = file->readBlock(Header::size()); if(data.size() < Header::size() || !data.startsWith(Header::fileIdentifier())) break; diff --git a/taglib/mpeg/id3v2/id3v2tag.h b/taglib/mpeg/id3v2/id3v2tag.h index 76ca73f1..af0efdc3 100644 --- a/taglib/mpeg/id3v2/id3v2tag.h +++ b/taglib/mpeg/id3v2/id3v2tag.h @@ -382,7 +382,7 @@ namespace TagLib { * the Header, the body of the tag (which contains the ExtendedHeader and * frames) and Footer. */ - void read(); + void read(TagLib::File *file, long offset); /*! * This is called by read to parse the body of the tag. It determines if an From 8c424badad17120d3e3eb60b2f0149c5e2799bfe Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 13:42:25 +0900 Subject: [PATCH 05/15] Avoid writing an empty ID3v2 tag in an AIFF file. --- taglib/riff/aiff/aifffile.cpp | 7 +++++-- tests/test_aiff.cpp | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index c5c7f881..57131d47 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -117,9 +117,12 @@ bool RIFF::AIFF::File::save() removeChunk("ID3 "); removeChunk("id3 "); + d->hasID3v2 = false; - setChunkData("ID3 ", d->tag->render()); - d->hasID3v2 = true; + if(tag() && !tag()->isEmpty()) { + setChunkData("ID3 ", d->tag->render()); + d->hasID3v2 = true; + } return true; } diff --git a/tests/test_aiff.cpp b/tests/test_aiff.cpp index 830b6787..b0204a2d 100644 --- a/tests/test_aiff.cpp +++ b/tests/test_aiff.cpp @@ -64,14 +64,23 @@ public: { RIFF::AIFF::File f(newname.c_str()); CPPUNIT_ASSERT(!f.hasID3v2Tag()); + f.tag()->setTitle(L"TitleXXX"); f.save(); + CPPUNIT_ASSERT(f.hasID3v2Tag()); } - { RIFF::AIFF::File f(newname.c_str()); CPPUNIT_ASSERT(f.hasID3v2Tag()); CPPUNIT_ASSERT_EQUAL(String(L"TitleXXX"), f.tag()->title()); + + f.tag()->setTitle(""); + f.save(); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); + } + { + RIFF::AIFF::File f(newname.c_str()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); } } From fcdf7c2ae279f5fca9f933ee7de8c853da7a6d54 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 13:46:43 +0900 Subject: [PATCH 06/15] Add some tests to check if the internal flags are updated when writing WAV files. --- tests/test_wav.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/test_wav.cpp b/tests/test_wav.cpp index d7bc4881..cdb0ca58 100644 --- a/tests/test_wav.cpp +++ b/tests/test_wav.cpp @@ -91,26 +91,29 @@ public: { RIFF::WAV::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); f.ID3v2Tag()->setTitle(L"Title"); f.ID3v2Tag()->setArtist(L"Artist"); f.save(); + CPPUNIT_ASSERT(f.hasID3v2Tag()); } - { RIFF::WAV::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasID3v2Tag()); CPPUNIT_ASSERT_EQUAL(String(L"Title"), f.ID3v2Tag()->title()); CPPUNIT_ASSERT_EQUAL(String(L"Artist"), f.ID3v2Tag()->artist()); f.ID3v2Tag()->setTitle(L""); f.ID3v2Tag()->setArtist(L""); f.save(); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); } - { RIFF::WAV::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasID3v2Tag()); CPPUNIT_ASSERT_EQUAL(String(L""), f.ID3v2Tag()->title()); CPPUNIT_ASSERT_EQUAL(String(L""), f.ID3v2Tag()->artist()); } @@ -124,26 +127,30 @@ public: { RIFF::WAV::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasInfoTag()); f.InfoTag()->setTitle(L"Title"); f.InfoTag()->setArtist(L"Artist"); f.save(); + CPPUNIT_ASSERT(f.hasInfoTag()); } - { RIFF::WAV::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasInfoTag()); CPPUNIT_ASSERT_EQUAL(String(L"Title"), f.InfoTag()->title()); CPPUNIT_ASSERT_EQUAL(String(L"Artist"), f.InfoTag()->artist()); f.InfoTag()->setTitle(L""); f.InfoTag()->setArtist(L""); f.save(); + CPPUNIT_ASSERT(!f.hasInfoTag()); } { RIFF::WAV::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasInfoTag()); CPPUNIT_ASSERT_EQUAL(String(L""), f.InfoTag()->title()); CPPUNIT_ASSERT_EQUAL(String(L""), f.InfoTag()->artist()); } From f9e558eef5ef8d158d1349db43701721fb20ad50 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 14:17:26 +0900 Subject: [PATCH 07/15] Avoid trying to remove tag chunks when an AIFF file doesn't have an ID3v2 tag. --- taglib/riff/aiff/aifffile.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index 57131d47..28f4b803 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -115,9 +115,11 @@ bool RIFF::AIFF::File::save() return false; } - removeChunk("ID3 "); - removeChunk("id3 "); - d->hasID3v2 = false; + if(d->hasID3v2) { + removeChunk("ID3 "); + removeChunk("id3 "); + d->hasID3v2 = false; + } if(tag() && !tag()->isEmpty()) { setChunkData("ID3 ", d->tag->render()); From a6701ddcdab3f21ed05961827673b991581b1547 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 15:43:18 +0900 Subject: [PATCH 08/15] Remove some private data members not needed to belong to private classes. --- taglib/mpeg/id3v1/id3v1tag.cpp | 45 +++++++++++++++++----------------- taglib/mpeg/id3v2/id3v2tag.cpp | 26 +++++++++----------- taglib/riff/wav/infotag.cpp | 36 ++++++++++++--------------- 3 files changed, 50 insertions(+), 57 deletions(-) diff --git a/taglib/mpeg/id3v1/id3v1tag.cpp b/taglib/mpeg/id3v1/id3v1tag.cpp index 4a7d50d6..dd32326f 100644 --- a/taglib/mpeg/id3v1/id3v1tag.cpp +++ b/taglib/mpeg/id3v1/id3v1tag.cpp @@ -32,6 +32,12 @@ using namespace TagLib; using namespace ID3v1; +namespace +{ + const ID3v1::StringHandler defaultStringHandler; + const ID3v1::StringHandler *stringHandler = &defaultStringHandler; +} + class ID3v1::Tag::TagPrivate { public: @@ -46,13 +52,8 @@ public: String comment; uchar track; uchar genre; - - static const StringHandler *stringHandler; }; -static const StringHandler defaultStringHandler; -const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler; - //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// @@ -68,12 +69,10 @@ String ID3v1::StringHandler::parse(const ByteVector &data) const ByteVector ID3v1::StringHandler::render(const String &s) const { - if(!s.isLatin1()) - { + if(s.isLatin1()) + return s.data(String::Latin1); + else return ByteVector(); - } - - return s.data(String::Latin1); } //////////////////////////////////////////////////////////////////////////////// @@ -103,11 +102,11 @@ ByteVector ID3v1::Tag::render() const ByteVector data; data.append(fileIdentifier()); - data.append(TagPrivate::stringHandler->render(d->title).resize(30)); - data.append(TagPrivate::stringHandler->render(d->artist).resize(30)); - data.append(TagPrivate::stringHandler->render(d->album).resize(30)); - data.append(TagPrivate::stringHandler->render(d->year).resize(4)); - data.append(TagPrivate::stringHandler->render(d->comment).resize(28)); + data.append(stringHandler->render(d->title).resize(30)); + data.append(stringHandler->render(d->artist).resize(30)); + data.append(stringHandler->render(d->album).resize(30)); + data.append(stringHandler->render(d->year).resize(4)); + data.append(stringHandler->render(d->comment).resize(28)); data.append(char(0)); data.append(char(d->track)); data.append(char(d->genre)); @@ -202,10 +201,10 @@ void ID3v1::Tag::setGenreNumber(TagLib::uint i) void ID3v1::Tag::setStringHandler(const StringHandler *handler) { - if (handler) - TagPrivate::stringHandler = handler; + if(handler) + stringHandler = handler; else - TagPrivate::stringHandler = &defaultStringHandler; + stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// @@ -231,16 +230,16 @@ void ID3v1::Tag::parse(const ByteVector &data) { int offset = 3; - d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + d->title = stringHandler->parse(data.mid(offset, 30)); offset += 30; - d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + d->artist = stringHandler->parse(data.mid(offset, 30)); offset += 30; - d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + d->album = stringHandler->parse(data.mid(offset, 30)); offset += 30; - d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4)); + d->year = stringHandler->parse(data.mid(offset, 4)); offset += 4; // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this @@ -251,7 +250,7 @@ void ID3v1::Tag::parse(const ByteVector &data) if(data[offset + 28] == 0 && data[offset + 29] != 0) { // ID3v1.1 detected - d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28)); + d->comment = stringHandler->parse(data.mid(offset, 28)); d->track = uchar(data[offset + 29]); } else diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index 636d9eb2..ac1bd66c 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -51,6 +51,15 @@ using namespace TagLib; using namespace ID3v2; +namespace +{ + const ID3v2::Latin1StringHandler defaultStringHandler; + const ID3v2::Latin1StringHandler *stringHandler = &defaultStringHandler; + + const long MinPaddingSize = 1024; + const long MaxPaddingSize = 1024 * 1024; +} + class ID3v2::Tag::TagPrivate { public: @@ -77,19 +86,8 @@ public: FrameListMap frameListMap; FrameList frameList; - - static const Latin1StringHandler *stringHandler; }; -static const Latin1StringHandler defaultStringHandler; -const ID3v2::Latin1StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler; - -namespace -{ - const long MinPaddingSize = 1024; - const long MaxPaddingSize = 1024 * 1024; -} - //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// @@ -648,15 +646,15 @@ ByteVector ID3v2::Tag::render(int version) const Latin1StringHandler const *ID3v2::Tag::latin1StringHandler() { - return TagPrivate::stringHandler; + return stringHandler; } void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler) { if(handler) - TagPrivate::stringHandler = handler; + stringHandler = handler; else - TagPrivate::stringHandler = &defaultStringHandler; + stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index 050ff37c..dbd9395e 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -31,8 +31,9 @@ using namespace TagLib; using namespace RIFF::Info; -namespace { - static bool isValidChunkID(const ByteVector &name) +namespace +{ + inline bool isValidChunkID(const ByteVector &name) { if(name.size() != 4) return false; @@ -44,17 +45,15 @@ namespace { return true; } + + const RIFF::Info::StringHandler defaultStringHandler; + const RIFF::Info::StringHandler *stringHandler = &defaultStringHandler; } class RIFF::Info::Tag::TagPrivate { public: - TagPrivate() - {} - FieldListMap fieldListMap; - - static const StringHandler *stringHandler; }; //////////////////////////////////////////////////////////////////////////////// @@ -83,19 +82,16 @@ ByteVector RIFF::Info::StringHandler::render(const String &s) const // public members //////////////////////////////////////////////////////////////////////////////// -static const StringHandler defaultStringHandler; -const RIFF::Info::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler; - -RIFF::Info::Tag::Tag(const ByteVector &data) - : TagLib::Tag() - , d(new TagPrivate()) +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() : + TagLib::Tag(), + d(new TagPrivate()) { } @@ -222,7 +218,7 @@ ByteVector RIFF::Info::Tag::render() const FieldListMap::ConstIterator it = d->fieldListMap.begin(); for(; it != d->fieldListMap.end(); ++it) { - ByteVector text = TagPrivate::stringHandler->render(it->second); + ByteVector text = stringHandler->render(it->second); if(text.isEmpty()) continue; @@ -244,9 +240,9 @@ ByteVector RIFF::Info::Tag::render() const void RIFF::Info::Tag::setStringHandler(const StringHandler *handler) { if(handler) - TagPrivate::stringHandler = handler; + stringHandler = handler; else - TagPrivate::stringHandler = &defaultStringHandler; + stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// @@ -263,7 +259,7 @@ void RIFF::Info::Tag::parse(const ByteVector &data) const ByteVector id = data.mid(p, 4); if(isValidChunkID(id)) { - const String text = TagPrivate::stringHandler->parse(data.mid(p + 8, size)); + const String text = stringHandler->parse(data.mid(p + 8, size)); d->fieldListMap[id] = text; } From bccd57a470179bd55ce1566718861665dbe5bcc5 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 16:21:58 +0900 Subject: [PATCH 09/15] Add const to an unchanged data member. --- taglib/riff/rifffile.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index 7d427a46..9aaf76ef 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -44,13 +44,11 @@ struct Chunk class RIFF::File::FilePrivate { public: - FilePrivate() : - endianness(BigEndian), - size(0) - { + FilePrivate(Endianness endianness) : + endianness(endianness), + size(0) {} - } - Endianness endianness; + const Endianness endianness; ByteVector type; TagLib::uint size; ByteVector format; @@ -71,20 +69,18 @@ RIFF::File::~File() // protected members //////////////////////////////////////////////////////////////////////////////// -RIFF::File::File(FileName file, Endianness endianness) : TagLib::File(file) +RIFF::File::File(FileName file, Endianness endianness) : + TagLib::File(file), + d(new FilePrivate(endianness)) { - d = new FilePrivate; - d->endianness = endianness; - if(isOpen()) read(); } -RIFF::File::File(IOStream *stream, Endianness endianness) : TagLib::File(stream) +RIFF::File::File(IOStream *stream, Endianness endianness) : + TagLib::File(stream), + d(new FilePrivate(endianness)) { - d = new FilePrivate; - d->endianness = endianness; - if(isOpen()) read(); } From eb6542bc8b46d074727fb38a6ecee5a5e2a4a31a Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 16:35:37 +0900 Subject: [PATCH 10/15] Unify some duplicate internal functions. --- taglib/riff/rifffile.cpp | 25 +++++------------ taglib/riff/riffutils.h | 55 +++++++++++++++++++++++++++++++++++++ taglib/riff/wav/infotag.cpp | 18 ++---------- 3 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 taglib/riff/riffutils.h diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index 9aaf76ef..1d834b04 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -23,13 +23,15 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include +#include + #include #include #include #include "rifffile.h" -#include -#include +#include "riffutils.h" using namespace TagLib; @@ -175,7 +177,7 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bo // Couldn't find an existing chunk, so let's create a new one. - uint i = d->chunks.size() - 1; + uint i = d->chunks.size() - 1; ulong offset = d->chunks[i].offset + d->chunks[i].size; // First we update the global size @@ -189,7 +191,7 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bo // And update our internal structure - if (offset & 1) { + if(offset & 1) { d->chunks[i].padding = 1; offset++; } @@ -231,19 +233,6 @@ void RIFF::File::removeChunk(const ByteVector &name) // 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); @@ -257,7 +246,7 @@ void RIFF::File::read() ByteVector chunkName = readBlock(4); uint chunkSize = readBlock(4).toUInt(bigEndian); - if(!isValidChunkID(chunkName)) { + if(!isValidChunkName(chunkName)) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID"); setValid(false); break; diff --git a/taglib/riff/riffutils.h b/taglib/riff/riffutils.h new file mode 100644 index 00000000..c9270dff --- /dev/null +++ b/taglib/riff/riffutils.h @@ -0,0 +1,55 @@ +/*************************************************************************** + 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 + { + static bool isValidChunkName(const ByteVector &name) + { + if(name.size() != 4) + return false; + + for(ByteVector::ConstIterator it = name.begin(); it != name.end(); ++it) { + const uchar c = static_cast(*it); + if(c < 32 || 127 < c) + return false; + } + + return true; + } + } +} + +#endif + +#endif diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index dbd9395e..00d1f1c5 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -27,25 +27,13 @@ #include #include "infotag.h" +#include "riffutils.h" using namespace TagLib; using namespace RIFF::Info; namespace { - inline 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; - } - const RIFF::Info::StringHandler defaultStringHandler; const RIFF::Info::StringHandler *stringHandler = &defaultStringHandler; } @@ -197,7 +185,7 @@ String RIFF::Info::Tag::fieldText(const ByteVector &id) const void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s) { // id must be four-byte long pure ascii string. - if(!isValidChunkID(id)) + if(!isValidChunkName(id)) return; if(!s.isEmpty()) @@ -258,7 +246,7 @@ void RIFF::Info::Tag::parse(const ByteVector &data) break; const ByteVector id = data.mid(p, 4); - if(isValidChunkID(id)) { + if(isValidChunkName(id)) { const String text = stringHandler->parse(data.mid(p + 8, size)); d->fieldListMap[id] = text; } From 59088096e6e4f32a5eeb716b3d9a5f3bbae2bd3c Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 17:18:50 +0900 Subject: [PATCH 11/15] Add some tests for M4V files. --- tests/data/blank_video.m4v | Bin 0 -> 15018 bytes tests/test_fileref.cpp | 5 +++++ tests/test_mp4.cpp | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 tests/data/blank_video.m4v diff --git a/tests/data/blank_video.m4v b/tests/data/blank_video.m4v new file mode 100644 index 0000000000000000000000000000000000000000..4bb15ded33f50b99b8887adbc62b2236fa18b860 GIT binary patch literal 15018 zcmeI2?`s@I7{{O8q^4rAXSvjfQ8y5%7O%{OgcPZ8sX<$)=o_VqN-nqCyQ8<+b9e7F zvFg02(3iebTZMoH75odtA1C-iMEXJm!BsZzMwD5afM#-$r_uIOd|Gv6FBM2Sk~U#4lkJ+2 zYdkHPmZ_nzCHAqUEVG^)Q^V6DtWX;qhf*mv7?Ogp}t0HM63AD34Ee*fXQ z@5lm`mfH!H!mobY^-@jo^Oz2f)z{pPM`f%({Px-@6y?6JD$RC#)=l!J-O!^l6exdB zFYGvpwmy#H)eh=UqBv4lDY3(Q^?sv@nnJctWw0d<`xr_(C=^O0=FIoh5HAH(u+}H6 zqk{*Bzrp?{#=qL~n?KJ2?7awMpUER9zmOJ;w=Nx#Sh&0zhse_YF{x&zgz;1qE6!x1 zMjrr}_zB}Oc3)lik)84$Mq2}83N{{OqiatwrSBf;b69QzbsDfv)#hDjxS0oztr3hm zf&JTk6=3!R_T__||5|z?sd3;bIGHkm2B=1vvE|dXY#!JPdEeA+e2#PDQyBT?iL7r% zL2oTv&G9IB+Cv|Ao@{qK=h-lDdkxQZR@a@Uf}q*)9(5Kf)oNu7to}c{O8Zn< zl~!MOSmZ2u$2*8;Qnty-_M<&@vhqlOnR7Bc-@ispY1Y11-0<-aj1N=1a;A4Ntr=Q(`K4WJ12iSn^PCkF>#53{+%~v6!%Q8H)i6 zQz=3LA!BxyA{QZFXDkLRZ!#4F71?JjCM+RiF<^<9ih&C6<%&>n%`K9t?l;!=Rr$H%bJ!e zT1qW9wH#=codec()); } + void testPropertiesM4V() + { + MP4::File f(TEST_FILE_PATH_C("blank_video.m4v")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(975, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(96, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + CPPUNIT_ASSERT_EQUAL(MP4::Properties::AAC, f.audioProperties()->codec()); + } + void testCheckValid() { MP4::File f(TEST_FILE_PATH_C("empty.aiff")); From 101a330d556acfa5816a0527ce8ae87a289043e9 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 30 Nov 2015 18:32:49 +0900 Subject: [PATCH 12/15] The new test wasn't called. --- tests/test_fileref.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index 5a927ecd..88f711a7 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -38,6 +38,7 @@ class TestFileRef : public CppUnit::TestFixture CPPUNIT_TEST(testMP4_1); CPPUNIT_TEST(testMP4_2); CPPUNIT_TEST(testMP4_3); + CPPUNIT_TEST(testMP4_4); CPPUNIT_TEST(testTrueAudio); CPPUNIT_TEST(testAPE); CPPUNIT_TEST(testWav); From 90f1f0316374fffdd276f986a70d935e7c4d457e Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Mon, 30 Nov 2015 14:09:15 +0200 Subject: [PATCH 13/15] fix pkgconfig file for cross compiling --- taglib.pc.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taglib.pc.cmake b/taglib.pc.cmake index 5ee50aa5..09402998 100644 --- a/taglib.pc.cmake +++ b/taglib.pc.cmake @@ -7,5 +7,5 @@ Name: TagLib Description: Audio meta-data library Requires: Version: ${TAGLIB_LIB_VERSION_STRING} -Libs: -L${LIB_INSTALL_DIR} -ltag -Cflags: -I${INCLUDE_INSTALL_DIR}/taglib +Libs: -L${dollar}{libdir} -ltag +Cflags: -I${dollar}{includedir}/taglib From b1c67fc5dceeb3f297ac14f5820e5a26c7388ef0 Mon Sep 17 00:00:00 2001 From: Festus Hagen Date: Sun, 29 Nov 2015 05:13:44 -0500 Subject: [PATCH 14/15] Silence ushort ambiguity errors --- taglib/toolkit/tstring.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/taglib/toolkit/tstring.cpp b/taglib/toolkit/tstring.cpp index 829fe477..18b44d1a 100644 --- a/taglib/toolkit/tstring.cpp +++ b/taglib/toolkit/tstring.cpp @@ -174,7 +174,7 @@ namespace if(length > 0) { if(swap) { for(size_t i = 0; i < length; ++i) - data[i] = Utils::byteSwap(static_cast(s[i])); + data[i] = Utils::byteSwap(static_cast(s[i])); } else { ::wmemcpy(&data[0], s, length); @@ -194,7 +194,7 @@ namespace } // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. - ushort bom; + TagLib::ushort bom; ::memcpy(&bom, s, 2); if(bom == 0xfeff) @@ -215,7 +215,7 @@ namespace data.resize(length / 2); for(size_t i = 0; i < length / 2; ++i) { - ushort c; + TagLib::ushort c; ::memcpy(&c, s, 2); if(swap) c = Utils::byteSwap(c); From 6966be42921695e1e7caa74ed578aefad2d4fe84 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Wed, 2 Dec 2015 09:13:10 +0900 Subject: [PATCH 15/15] Use a standard type rather than TagLib::ulonglong. TagLib::ulonglong is not used in the public headers, so the changes are trivial. --- taglib/flac/flacproperties.cpp | 4 ++-- taglib/riff/rifffile.cpp | 4 ++-- taglib/toolkit/tbytevector.cpp | 26 +++++++++++++------------- taglib/toolkit/tutils.h | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/taglib/flac/flacproperties.cpp b/taglib/flac/flacproperties.cpp index efc9fa1b..9f0f9256 100644 --- a/taglib/flac/flacproperties.cpp +++ b/taglib/flac/flacproperties.cpp @@ -159,8 +159,8 @@ void FLAC::Properties::read(const ByteVector &data, long streamLength) // The last 4 bits are the most significant 4 bits for the 36 bit // stream length in samples. (Audio files measured in days) - const ulonglong hi = flags & 0xf; - const ulonglong lo = data.toUInt(pos, true); + const unsigned long long hi = flags & 0xf; + const unsigned long long lo = data.toUInt(pos, true); pos += 4; d->sampleFrames = (hi << 32) | lo; diff --git a/taglib/riff/rifffile.cpp b/taglib/riff/rifffile.cpp index 1d834b04..8317a57e 100644 --- a/taglib/riff/rifffile.cpp +++ b/taglib/riff/rifffile.cpp @@ -252,7 +252,7 @@ void RIFF::File::read() break; } - if(static_cast(tell()) + chunkSize > static_cast(length())) { + if(static_cast(tell()) + chunkSize > length()) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)"); setValid(false); break; @@ -278,8 +278,8 @@ void RIFF::File::read() chunk.padding = 1; } } - d->chunks.push_back(chunk); + d->chunks.push_back(chunk); } } diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index c65962da..909a2aae 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -277,15 +277,15 @@ long double toFloat80(const ByteVector &v, size_t offset) const int exponent = ((bytes[0] & 0x7F) << 8) | bytes[1]; // 64-bit fraction. Leading 1 is explicit. - const ulonglong fraction - = (static_cast(bytes[2]) << 56) - | (static_cast(bytes[3]) << 48) - | (static_cast(bytes[4]) << 40) - | (static_cast(bytes[5]) << 32) - | (static_cast(bytes[6]) << 24) - | (static_cast(bytes[7]) << 16) - | (static_cast(bytes[8]) << 8) - | (static_cast(bytes[9])); + const unsigned long long fraction + = (static_cast(bytes[2]) << 56) + | (static_cast(bytes[3]) << 48) + | (static_cast(bytes[4]) << 40) + | (static_cast(bytes[5]) << 32) + | (static_cast(bytes[6]) << 24) + | (static_cast(bytes[7]) << 16) + | (static_cast(bytes[8]) << 8) + | (static_cast(bytes[9])); long double val; if(exponent == 0 && fraction == 0) @@ -384,12 +384,12 @@ ByteVector ByteVector::fromFloat32BE(float value) ByteVector ByteVector::fromFloat64LE(double value) { - return fromFloat(value); + return fromFloat(value); } ByteVector ByteVector::fromFloat64BE(double value) { - return fromFloat(value); + return fromFloat(value); } //////////////////////////////////////////////////////////////////////////////// @@ -756,12 +756,12 @@ float ByteVector::toFloat32BE(size_t offset) const double ByteVector::toFloat64LE(size_t offset) const { - return toFloat(*this, offset); + return toFloat(*this, offset); } double ByteVector::toFloat64BE(size_t offset) const { - return toFloat(*this, offset); + return toFloat(*this, offset); } long double ByteVector::toFloat80LE(size_t offset) const diff --git a/taglib/toolkit/tutils.h b/taglib/toolkit/tutils.h index 0655342a..9855ed91 100644 --- a/taglib/toolkit/tutils.h +++ b/taglib/toolkit/tutils.h @@ -134,7 +134,7 @@ namespace TagLib /*! * Reverses the order of bytes in an 64-bit integer. */ - inline ulonglong byteSwap(ulonglong x) + inline unsigned long long byteSwap(unsigned long long x) { #if defined(HAVE_BOOST_BYTESWAP)