diff --git a/taglib/ape/apefile.cpp b/taglib/ape/apefile.cpp index 4e4e0cb8..0e7f6734 100644 --- a/taglib/ape/apefile.cpp +++ b/taglib/ape/apefile.cpp @@ -57,7 +57,6 @@ public: APELocation(-1), APESize(0), ID3v1Location(-1), - tag(2), properties(0), hasAPE(false), hasID3v1(false) {} @@ -72,7 +71,7 @@ public: offset_t ID3v1Location; - TagUnion tag; + DoubleTagUnion tag; AudioProperties *properties; diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index 9e46bcfa..42bd33b5 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -57,7 +57,6 @@ public: ID3v2Location(-1), ID3v2OriginalSize(0), ID3v1Location(-1), - tag(3), properties(0), flacStart(0), streamStart(0), @@ -84,7 +83,7 @@ public: offset_t ID3v1Location; - TagUnion tag; + TripleTagUnion tag; AudioProperties *properties; ByteVector streamInfoData; @@ -245,11 +244,7 @@ bool FLAC::File::save() ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) { - if(!create || d->tag[FlacID3v2Index]) - return static_cast(d->tag[FlacID3v2Index]); - - d->tag.set(FlacID3v2Index, new ID3v2::Tag); - return static_cast(d->tag[FlacID3v2Index]); + return d->tag.access(FlacID3v2Index, create); } ID3v1::Tag *FLAC::File::ID3v1Tag(bool create) diff --git a/taglib/mpc/mpcfile.cpp b/taglib/mpc/mpcfile.cpp index 1b2908d1..f109e5f1 100644 --- a/taglib/mpc/mpcfile.cpp +++ b/taglib/mpc/mpcfile.cpp @@ -52,7 +52,6 @@ public: ID3v2Header(0), ID3v2Location(-1), ID3v2Size(0), - tag(2), properties(0), scanned(false), hasAPE(false), @@ -74,7 +73,7 @@ public: offset_t ID3v2Location; uint ID3v2Size; - TagUnion tag; + DoubleTagUnion tag; AudioProperties *properties; bool scanned; diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index 749a7749..54eef6a4 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -55,7 +55,6 @@ public: APEFooterLocation(-1), APEOriginalSize(0), ID3v1Location(-1), - tag(3), hasID3v2(false), hasID3v1(false), hasAPE(false), @@ -80,7 +79,7 @@ public: offset_t ID3v1Location; - TagUnion tag; + TripleTagUnion tag; // These indicate whether the file *on disk* has these tags, not if // this data structure does. This is used in computing offsets. diff --git a/taglib/riff/wav/infotag.cpp b/taglib/riff/wav/infotag.cpp index f0389154..fac8785c 100644 --- a/taglib/riff/wav/infotag.cpp +++ b/taglib/riff/wav/infotag.cpp @@ -1,6 +1,6 @@ /*************************************************************************** copyright : (C) 2012 by Tsuda Kageyu - email : wheeler@kde.org + email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** @@ -31,14 +31,15 @@ using namespace TagLib; using namespace RIFF::Info; -namespace { - static bool isValidChunkID(const ByteVector &name) +namespace +{ + 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) + if(name[i] < 32 || 127 < name[i]) return false; } @@ -86,7 +87,9 @@ ByteVector RIFF::Info::StringHandler::render(const String &s) const // public members //////////////////////////////////////////////////////////////////////////////// -RIFF::Info::Tag::Tag(const ByteVector &data) : TagLib::Tag() +RIFF::Info::Tag::Tag(const ByteVector &data) + : TagLib::Tag() + , d(new TagPrivate()) { parse(data); } @@ -193,7 +196,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. + // id must be four-byte long pure ASCII string. if(!isValidChunkID(id)) return; diff --git a/taglib/riff/wav/wavfile.cpp b/taglib/riff/wav/wavfile.cpp index 6a391431..50769409 100644 --- a/taglib/riff/wav/wavfile.cpp +++ b/taglib/riff/wav/wavfile.cpp @@ -45,8 +45,7 @@ class RIFF::WAV::File::FilePrivate public: FilePrivate() : properties(0), - tagChunkID("ID3 "), - tag(2) + tagChunkID("ID3 ") { } @@ -59,7 +58,7 @@ public: ByteVector tagChunkID; - TagUnion tag; + DoubleTagUnion tag; }; //////////////////////////////////////////////////////////////////////////////// @@ -87,9 +86,9 @@ RIFF::WAV::File::~File() delete d; } -ID3v2::Tag *RIFF::WAV::File::tag() const +TagLib::Tag *RIFF::WAV::File::tag() const { - return ID3v2Tag(); + return &d->tag; } ID3v2::Tag *RIFF::WAV::File::ID3v2Tag() const diff --git a/taglib/riff/wav/wavfile.h b/taglib/riff/wav/wavfile.h index 6c1fa77d..476e030b 100644 --- a/taglib/riff/wav/wavfile.h +++ b/taglib/riff/wav/wavfile.h @@ -94,12 +94,10 @@ namespace TagLib { 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. + * Returns the Tag for this file. This will be an ID3v2 tag, an INFO tag + * or a combination of the two. */ - ID3v2::Tag *tag() const; + virtual TagLib::Tag *tag() const; /*! * Returns the ID3v2 Tag for this file. diff --git a/taglib/tagunion.cpp b/taglib/tagunion.cpp index fe7631d0..904ec17b 100644 --- a/taglib/tagunion.cpp +++ b/taglib/tagunion.cpp @@ -27,168 +27,184 @@ #include "tstringlist.h" #include "tpropertymap.h" -using namespace TagLib; - -namespace -{ - typedef std::vector > TagVector; - typedef TagVector::iterator TagIterator; - typedef TagVector::const_iterator TagConstIterator; -} #define stringUnion(method) \ - for(TagConstIterator it = d->tags.begin(); it != d->tags.end(); ++it) { \ - String val = (*it) ? (*it)->method() : String::null; \ + for(size_t j = 0; j < COUNT; ++j) { \ + String val = d->tags[j] ? d->tags[j]->method() : String::null; \ if(!val.isEmpty()) \ return val; \ } \ return String::null; #define numberUnion(method) \ - for(TagConstIterator it = d->tags.begin(); it != d->tags.end(); ++it) { \ - uint val = (*it) ? (*it)->method() : 0; \ + for(size_t j = 0; j < COUNT; ++j) { \ + uint val = d->tags[j] ? d->tags[j]->method() : 0; \ if(val > 0) \ return val; \ } \ return 0; #define setUnion(method, value) \ - for(TagIterator it = d->tags.begin(); it != d->tags.end(); ++it) { \ - if(*it) \ - (*it)->set##method(value); \ + for(size_t j = 0; j < COUNT; ++j) { \ + if(d->tags[j]) \ + d->tags[j]->set##method(value); \ } -class TagUnion::TagUnionPrivate +namespace TagLib { -public: - TagUnionPrivate(size_t count) - : tags(count) + template + class TagUnion::TagUnionPrivate + { + public: + NonRefCountPtr tags[COUNT]; + }; + + template + TagUnion::TagUnion() + : d(new TagUnionPrivate()) { } - TagVector tags; -}; - -TagUnion::TagUnion(size_t count) - : d(new TagUnionPrivate(count)) -{ -} - -TagUnion::~TagUnion() -{ -} - -Tag *TagUnion::operator[](size_t index) const -{ - return tag(index); -} - -Tag *TagUnion::tag(size_t index) const -{ - return d->tags[index].get(); -} - -void TagUnion::set(size_t index, Tag *tag) -{ - d->tags[index].reset(tag); -} - -PropertyMap TagUnion::properties() const -{ - for(TagConstIterator it = d->tags.begin(); it != d->tags.end(); ++it) { - if(*it) - return (*it)->properties(); + template + TagUnion::~TagUnion() + { } - return PropertyMap(); -} - -void TagUnion::removeUnsupportedProperties(const StringList &unsupported) -{ - for(TagIterator it = d->tags.begin(); it != d->tags.end(); ++it) { - if(*it) - (*it)->removeUnsupportedProperties(unsupported); - } -} - - -String TagUnion::title() const -{ - stringUnion(title); -} - -String TagUnion::artist() const -{ - stringUnion(artist); -} - -String TagUnion::album() const -{ - stringUnion(album); -} - -String TagUnion::comment() const -{ - stringUnion(comment); -} - -String TagUnion::genre() const -{ - stringUnion(genre); -} - -TagLib::uint TagUnion::year() const -{ - numberUnion(year); -} - -TagLib::uint TagUnion::track() const -{ - numberUnion(track); -} - -void TagUnion::setTitle(const String &s) -{ - setUnion(Title, s); -} - -void TagUnion::setArtist(const String &s) -{ - setUnion(Artist, s); -} - -void TagUnion::setAlbum(const String &s) -{ - setUnion(Album, s); -} - -void TagUnion::setComment(const String &s) -{ - setUnion(Comment, s); -} - -void TagUnion::setGenre(const String &s) -{ - setUnion(Genre, s); -} - -void TagUnion::setYear(uint i) -{ - setUnion(Year, i); -} - -void TagUnion::setTrack(uint i) -{ - setUnion(Track, i); -} - -bool TagUnion::isEmpty() const -{ - for(TagIterator it = d->tags.begin(); it != d->tags.end(); ++it) { - if(*it && !(*it)->isEmpty()) - return false; + template + Tag *TagUnion::operator[](size_t index) const + { + return tag(index); } - return true; -} + template + Tag *TagUnion::tag(size_t index) const + { + return d->tags[index].get(); + } + template + void TagUnion::set(size_t index, Tag *tag) + { + d->tags[index].reset(tag); + } + + template + PropertyMap TagUnion::properties() const + { + for(size_t i = 0; i < COUNT; ++i) { + if(d->tags[i]) + return d->tags[i]->properties(); + } + + return PropertyMap(); + } + + template + void TagUnion::removeUnsupportedProperties(const StringList &unsupported) + { + for(size_t i = 0; i < COUNT; ++i) { + if(d->tags[i]) + d->tags[i]->removeUnsupportedProperties(unsupported); + } + } + + template + String TagUnion::title() const + { + stringUnion(title); + } + + template + String TagUnion::artist() const + { + stringUnion(artist); + } + + template + String TagUnion::album() const + { + stringUnion(album); + } + + template + String TagUnion::comment() const + { + stringUnion(comment); + } + + template + String TagUnion::genre() const + { + stringUnion(genre); + } + + template + TagLib::uint TagUnion::year() const + { + numberUnion(year); + } + + template + TagLib::uint TagUnion::track() const + { + numberUnion(track); + } + + template + void TagUnion::setTitle(const String &s) + { + setUnion(Title, s); + } + + template + void TagUnion::setArtist(const String &s) + { + setUnion(Artist, s); + } + + template + void TagUnion::setAlbum(const String &s) + { + setUnion(Album, s); + } + + template + void TagUnion::setComment(const String &s) + { + setUnion(Comment, s); + } + + template + void TagUnion::setGenre(const String &s) + { + setUnion(Genre, s); + } + + template + void TagUnion::setYear(uint i) + { + setUnion(Year, i); + } + + template + void TagUnion::setTrack(uint i) + { + setUnion(Track, i); + } + + template + bool TagUnion::isEmpty() const + { + for(size_t i = 0; i < COUNT; ++i) { + if(d->tags[i] && !d->tags[i]->isEmpty()) + return false; + } + + return true; + } + + // All the versions of TagUnion should be explicitly instantiated here. + + template class TagUnion<2>; + template class TagUnion<3>; +} diff --git a/taglib/tagunion.h b/taglib/tagunion.h index 5479e71a..b7610621 100644 --- a/taglib/tagunion.h +++ b/taglib/tagunion.h @@ -36,6 +36,7 @@ namespace TagLib { * \internal */ + template class TagUnion : public Tag { public: @@ -45,7 +46,7 @@ namespace TagLib { /*! * Creates a TagLib::Tag that is the union of \a count tags. */ - TagUnion(size_t count); + TagUnion(); virtual ~TagUnion(); @@ -85,12 +86,15 @@ namespace TagLib { } private: - TagUnion(const Tag &); - TagUnion &operator=(const Tag &); - class TagUnionPrivate; NonRefCountPtr d; }; + + // If you add a new typedef here, add a corresponding explicit instantiation + // at the end of tagunion.cpp as well. + + typedef TagUnion<2> DoubleTagUnion; + typedef TagUnion<3> TripleTagUnion; } #endif diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 8663dd53..8018f779 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -312,7 +312,8 @@ inline T toNumber(const ByteVector &v, size_t offset) static const bool swap = (ENDIAN == LittleEndian); #endif - if(LENGTH >= sizeof(T) && offset + LENGTH <= v.size()) { + if(LENGTH >= sizeof(T) && offset + LENGTH <= v.size()) + { // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. T tmp; ::memcpy(&tmp, v.data() + offset, sizeof(T)); @@ -322,7 +323,8 @@ inline T toNumber(const ByteVector &v, size_t offset) else return tmp; } - else { + else if(offset < v.size()) + { const size_t length = std::min(LENGTH, v.size() - offset); T sum = 0; for(size_t i = 0; i < length; i++) { @@ -332,6 +334,11 @@ inline T toNumber(const ByteVector &v, size_t offset) return sum; } + else + { + debug("toNumber() - offset is out of range. Returning 0."); + return 0; + } } template diff --git a/taglib/trueaudio/trueaudiofile.cpp b/taglib/trueaudio/trueaudiofile.cpp index b21455a3..93bf7183 100644 --- a/taglib/trueaudio/trueaudiofile.cpp +++ b/taglib/trueaudio/trueaudiofile.cpp @@ -54,7 +54,6 @@ public: ID3v2Location(-1), ID3v2OriginalSize(0), ID3v1Location(-1), - tag(2), properties(0), hasID3v1(false), hasID3v2(false) {} @@ -70,7 +69,7 @@ public: offset_t ID3v1Location; - TagUnion tag; + DoubleTagUnion tag; AudioProperties *properties; diff --git a/taglib/wavpack/wavpackfile.cpp b/taglib/wavpack/wavpackfile.cpp index b9d5f055..b174ef53 100644 --- a/taglib/wavpack/wavpackfile.cpp +++ b/taglib/wavpack/wavpackfile.cpp @@ -53,7 +53,6 @@ public: APELocation(-1), APESize(0), ID3v1Location(-1), - tag(2), properties(0), hasAPE(false), hasID3v1(false) {} @@ -68,7 +67,7 @@ public: offset_t ID3v1Location; - TagUnion tag; + DoubleTagUnion tag; AudioProperties *properties;