diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp index 6a9d760b..d1336d22 100644 --- a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -25,7 +25,7 @@ #include #include - +#include #include "textidentificationframe.h" #include "tpropertymap.h" #include "id3v1genres.h" @@ -321,6 +321,14 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) checkFields(); } +UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : + TextIdentificationFrame("TXXX", encoding), + d(0) +{ + setDescription(description); + setText(values); +} + String UserTextIdentificationFrame::toString() const { return "[" + description() + "] " + fieldList().toString(); @@ -378,10 +386,12 @@ PropertyMap UserTextIdentificationFrame::asProperties() const String key = map.prepareKey(tagName); if(key.isNull()) // this frame's description is not a valid PropertyMap key -> add to unsupported list map.unsupportedData().append(L"TXXX/" + description()); - else - for(StringList::ConstIterator it = fieldList().begin(); it != fieldList().end(); ++it) + else { + StringList v = fieldList(); + for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it) if(*it != description()) map.insert(key, *it); + } return map; } diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.h b/taglib/mpeg/id3v2/frames/textidentificationframe.h index b82e7d3a..283f0c72 100644 --- a/taglib/mpeg/id3v2/frames/textidentificationframe.h +++ b/taglib/mpeg/id3v2/frames/textidentificationframe.h @@ -253,9 +253,9 @@ namespace TagLib { /*! * Creates a user defined text identification frame with the given \a description - * and \a text. + * and \a values. */ - UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::Latin1); + UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8); virtual String toString() const; diff --git a/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/taglib/mpeg/id3v2/frames/urllinkframe.cpp index db872db2..f06a04dd 100644 --- a/taglib/mpeg/id3v2/frames/urllinkframe.cpp +++ b/taglib/mpeg/id3v2/frames/urllinkframe.cpp @@ -26,6 +26,7 @@ ***************************************************************************/ #include "urllinkframe.h" +#include "id3v2tag.h" #include #include #include @@ -167,6 +168,17 @@ PropertyMap UserUrlLinkFrame::asProperties() const return map; } +UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static +{ + FrameList l = tag->frameList("WXXX"); + for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) { + UserUrlLinkFrame *f = dynamic_cast(*it); + if(f && f->description() == description) + return f; + } + return 0; +} + void UserUrlLinkFrame::parseFields(const ByteVector &data) { if(data.size() < 2) { diff --git a/taglib/mpeg/id3v2/frames/urllinkframe.h b/taglib/mpeg/id3v2/frames/urllinkframe.h index 4eea36b3..7ac966b2 100644 --- a/taglib/mpeg/id3v2/frames/urllinkframe.h +++ b/taglib/mpeg/id3v2/frames/urllinkframe.h @@ -161,6 +161,12 @@ namespace TagLib { */ PropertyMap asProperties() const; + /*! + * Searches for the user defined url frame with the description \a description + * in \a tag. This returns null if no matching frames were found. + */ + static UserUrlLinkFrame *find(Tag *tag, const String &description); + protected: virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index 05d58f48..e6be1f91 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -337,11 +337,42 @@ void ID3v2::Tag::removeFrames(const ByteVector &id) PropertyMap ID3v2::Tag::properties() const { PropertyMap properties; - for(FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) - properties.merge((*it)->asProperties()); + + for(FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) { + PropertyMap props = (*it)->asProperties(); + debug(props); + properties.merge(props); + } return properties; } +void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties) +{ + // entries of unsupportedData() are usually frame IDs which are not supported + // by the PropertyMap interface. Three special cases exist: TXXX, WXXX, and COMM + // frames may also be unsupported if their description() is not a valid key. + for(StringList::ConstIterator it = properties.begin(); it != properties.end(); ++it){ + ByteVector id = it->substr(0,4).data(String::Latin1); + if(id == "TXXX") { + String description = it->substr(5); + Frame *frame = UserTextIdentificationFrame::find(this, description); + if(frame) + removeFrame(frame); + } else if(id == "WXXX") { + String description = it->substr(5); + Frame *frame = UserUrlLinkFrame::find(this, description); + if(frame) + removeFrame(frame); + } else if(id == "COMM") { + String description = it->substr(5); + Frame *frame = CommentsFrame::findByDescription(this, description); + if(frame) + removeFrame(frame); + } else + removeFrames(id); // there should be only one frame with "id" + } +} + PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps) { FrameList framesToDelete; diff --git a/taglib/toolkit/tlist.h b/taglib/toolkit/tlist.h index dce0e1c6..0099dad5 100644 --- a/taglib/toolkit/tlist.h +++ b/taglib/toolkit/tlist.h @@ -227,6 +227,11 @@ namespace TagLib { */ bool operator==(const List &l) const; + /*! + * Compares this list with \a l and returns true if the lists differ. + */ + bool operator!=(const List &l) const; + protected: /* * If this List is being shared via implicit sharing, do a deep copy of the diff --git a/taglib/toolkit/tlist.tcc b/taglib/toolkit/tlist.tcc index a11887d8..37817f05 100644 --- a/taglib/toolkit/tlist.tcc +++ b/taglib/toolkit/tlist.tcc @@ -300,6 +300,12 @@ bool List::operator==(const List &l) const return d->list == l.d->list; } +template +bool List::operator!=(const List &l) const +{ + return d->list != l.d->list; +} + //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/toolkit/tpropertymap.cpp b/taglib/toolkit/tpropertymap.cpp index 4868f2d0..8dab7756 100644 --- a/taglib/toolkit/tpropertymap.cpp +++ b/taglib/toolkit/tpropertymap.cpp @@ -20,7 +20,6 @@ ***************************************************************************/ #include "tpropertymap.h" - using namespace TagLib; @@ -90,18 +89,34 @@ PropertyMap::ConstIterator PropertyMap::find(const String &key) const bool PropertyMap::contains(const String &key) const { String realKey = prepareKey(key); - // we consider keys with empty value list as not present - if(realKey.isNull() || SimplePropertyMap::operator[](realKey).isEmpty()) + if(realKey.isNull()) return false; return SimplePropertyMap::contains(realKey); } +bool PropertyMap::contains(const PropertyMap &other) const +{ + for(ConstIterator it = other.begin(); it != other.end(); ++it) { + if(!SimplePropertyMap::contains(it->first)) + return false; + if ((*this)[it->first] != it->second) + return false; + } + return true; +} + PropertyMap &PropertyMap::erase(const String &key) { String realKey = prepareKey(key); - if(realKey.isNull()) - return *this; - SimplePropertyMap::erase(realKey); + if(!realKey.isNull()) + SimplePropertyMap::erase(realKey); + return *this; +} + +PropertyMap &PropertyMap::erase(const PropertyMap &other) +{ + for(ConstIterator it = other.begin(); it != other.end(); ++it) + erase(it->first); return *this; } @@ -126,6 +141,26 @@ StringList &PropertyMap::operator[](const String &key) return SimplePropertyMap::operator[](realKey); } +bool PropertyMap::operator==(const PropertyMap &other) const +{ + for(ConstIterator it = other.begin(); it != other.end(); ++it) { + ConstIterator thisFind = find(it->first); + if( thisFind == end() || (thisFind->second != it->second) ) + return false; + } + for(ConstIterator it = begin(); it != end(); ++it) { + ConstIterator otherFind = other.find(it->first); + if( otherFind == other.end() || (otherFind->second != it->second) ) + return false; + } + return unsupported == other.unsupported; +} + +bool PropertyMap::operator!=(const PropertyMap &other) const +{ + return !(*this == other); +} + void PropertyMap::removeEmpty() { StringList emptyKeys;