From d2c43d71748cdb27e8b9f48a5c60dd71be11293d Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Tue, 14 Feb 2012 21:27:14 +0100 Subject: [PATCH] ID3 interface complete; vorbis done; wav done --- taglib/mpeg/id3v2/frames/commentsframe.cpp | 4 +- taglib/mpeg/id3v2/frames/commentsframe.h | 8 +- .../id3v2/frames/textidentificationframe.cpp | 17 +- .../id3v2/frames/textidentificationframe.h | 14 ++ .../frames/unsynchronizedlyricsframe.cpp | 8 +- .../id3v2/frames/unsynchronizedlyricsframe.h | 11 ++ taglib/mpeg/id3v2/frames/urllinkframe.cpp | 2 +- taglib/mpeg/id3v2/id3v2frame.cpp | 66 ++++++- taglib/mpeg/id3v2/id3v2frame.h | 42 ++++ taglib/mpeg/id3v2/id3v2tag.cpp | 184 ++++-------------- taglib/ogg/flac/oggflacfile.cpp | 10 - taglib/ogg/flac/oggflacfile.h | 12 -- taglib/ogg/speex/speexfile.cpp | 10 - taglib/ogg/speex/speexfile.h | 11 -- taglib/ogg/vorbis/vorbisfile.cpp | 8 +- taglib/ogg/vorbis/vorbisfile.h | 12 +- taglib/riff/aiff/aifffile.cpp | 9 +- taglib/riff/aiff/aifffile.h | 12 +- taglib/riff/wav/wavfile.cpp | 8 +- taglib/riff/wav/wavfile.h | 12 +- taglib/toolkit/tpropertymap.h | 11 ++ 21 files changed, 238 insertions(+), 233 deletions(-) diff --git a/taglib/mpeg/id3v2/frames/commentsframe.cpp b/taglib/mpeg/id3v2/frames/commentsframe.cpp index 5730b753..adc773ea 100644 --- a/taglib/mpeg/id3v2/frames/commentsframe.cpp +++ b/taglib/mpeg/id3v2/frames/commentsframe.cpp @@ -109,7 +109,7 @@ void CommentsFrame::setTextEncoding(String::Type encoding) d->textEncoding = encoding; } -PropertyMap CommentsFrame::asDescription() const +PropertyMap CommentsFrame::asProperties() const { String key = PropertyMap::prepareKey(description()); PropertyMap map; @@ -118,7 +118,7 @@ PropertyMap CommentsFrame::asDescription() const if(key.isNull()) map.unsupportedData().append(L"COMM/" + description()); else - map.insert(key, text()); + map.insert("COMMENT:" + key, text()); return map; } diff --git a/taglib/mpeg/id3v2/frames/commentsframe.h b/taglib/mpeg/id3v2/frames/commentsframe.h index 30d21ca1..f65f6f01 100644 --- a/taglib/mpeg/id3v2/frames/commentsframe.h +++ b/taglib/mpeg/id3v2/frames/commentsframe.h @@ -137,15 +137,15 @@ namespace TagLib { void setTextEncoding(String::Type encoding); /*! - * Parses this frame as PropertyMap. - * - description() will be used as key - * - if description() is empty, the key will be "COMMENT" + * Parses this frame as PropertyMap with a single key. + * - if description() is empty or "COMMENT", the key will be "COMMENT" * - if description() is not a valid PropertyMap key, the frame will be * marked unsupported by an entry "COMM/" in the unsupportedData() * attribute of the returned map. + * - otherwise, the key will be "COMMENT:" * - The single value will be the frame's text(). */ - PropertyMap asDescription() const; + PropertyMap asProperties() const; /*! * Comments each have a unique description. This searches for a comment diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp index f3aeb083..29943c96 100644 --- a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -59,7 +59,7 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static { - TextIdentificationFrame* frame = TextIdentificationFrame("TIPL"); + TextIdentificationFrame *frame = TextIdentificationFrame("TIPL"); StringList l; for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ l.append(it->first); @@ -68,6 +68,21 @@ TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const Property frame->setText(l); return frame; } + +TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static +{ + TextIdentificationFrame *frame = TextIdentificationFrame("TMCL"); + StringList l; + for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ + if(!it->first.startsWith(instrumentPrefix)) // should not happen + continue; + l.append(it->first.substr(instrumentPrefix.size())); + l.append(it->second.toString(",")); + } + frame->setText(l); + return frame; +} + TextIdentificationFrame::~TextIdentificationFrame() { delete d; diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.h b/taglib/mpeg/id3v2/frames/textidentificationframe.h index fc48a99f..b82e7d3a 100644 --- a/taglib/mpeg/id3v2/frames/textidentificationframe.h +++ b/taglib/mpeg/id3v2/frames/textidentificationframe.h @@ -131,6 +131,13 @@ namespace TagLib { */ static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties); + /*! + * This is a special factory method to create a TMCL (musician credits list) + * frame from the given \a properties. Will parse key=[list of values] data + * into the TMCL format as specified in the ID3 standard, where key should be + * of the form instrumentPrefix:instrument. + */ + static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties); /*! * Destroys this TextIdentificationFrame instance. */ @@ -186,6 +193,7 @@ namespace TagLib { * to the corresponding key used in a TIPL ID3 frame to describe that role. */ static const KeyConversionMap &involvedPeopleMap(); + PropertyMap asProperties() const; protected: @@ -243,6 +251,12 @@ namespace TagLib { */ explicit UserTextIdentificationFrame(const ByteVector &data); + /*! + * Creates a user defined text identification frame with the given \a description + * and \a text. + */ + UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::Latin1); + virtual String toString() const; /*! diff --git a/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp b/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp index b3a9b3da..e5142566 100644 --- a/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp +++ b/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp @@ -113,8 +113,14 @@ void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding) PropertyMap UnsynchronizedLyricsFrame::asProperties() const { + String key = PropertyMap::prepareKey(description()); PropertyMap map; - map.insert("LYRICS", text()); + if(key.isEmpty()) + key = "LYRICS"; + if(key.isNull()) + map.unsupportedData().append(L"USLT/" + description()); + else + map.insert("LYRICS:" + key, text()); return map; } diff --git a/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h b/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h index f13134c4..03648ee4 100644 --- a/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h +++ b/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h @@ -139,6 +139,17 @@ namespace TagLib { * Parses this frame as PropertyMap. The returned map will contain a single key * "LYRICS" with the text() as single value. */ + /*! + * Parses this frame as PropertyMap with a single key. + * - if description() is empty or "LYRICS", the key will be "LYRICS" + * - if description() is not a valid PropertyMap key, the frame will be + * marked unsupported by an entry "USLT/" in the unsupportedData() + * attribute of the returned map. + * - otherwise, the key will be "LYRICS:" + * - The single value will be the frame's text(). + * Note that currently the language() field is not supported by the PropertyMap + * interface. + */ PropertyMap asProperties() const; protected: diff --git a/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/taglib/mpeg/id3v2/frames/urllinkframe.cpp index b1800697..c0a771e1 100644 --- a/taglib/mpeg/id3v2/frames/urllinkframe.cpp +++ b/taglib/mpeg/id3v2/frames/urllinkframe.cpp @@ -162,7 +162,7 @@ PropertyMap UserUrlLinkFrame::asProperties() const if(key.isNull()) map.unsupportedData().append(L"WXXX/" + description()); else - map.insert(key, url()); + map.insert("URL:" + key, url()); return map; } diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index bf33fa8e..25e599aa 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -96,10 +96,54 @@ ByteVector Frame::textDelimiter(String::Type t) return d; } +String TextIdentificationFrame::instrumentPrefix("PERFORMER:"); +String TextIdentificationFrame::commentPrefix("COMMENT:"); +String TextIdentificationFrame::urlPrefix("URL:"); + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// +Frame *Frame::createTextualFrame(const String &key, const StringList &values) //static +{ + // check if the key is contained in the key<=>frameID mapping + ByteVector frameID = keyToFrameID(key); + if(!frameID.isNull()) { + if(frameID[0] == 'T'){ // text frame + TextIdentificationFrame* frame = TextIdentificationFrame(frameID, String::UTF8); + frame->setText(values); + return frame; + } else if(values.size() == 1){ // URL frame (not WXXX); support only one value + UrlLinkFrame* frame = UrlLinkFrame(frameID); + frame->setUrl(values.front()); + return frame; + } + } + // now we check if it's one of the "special" cases: + // -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS) + if(key == "LYRICS" && values.size() == 1){ + UnsynchronizedLyricsFrame *frame = UnsynchronizedLyricsFrame(); + frame->setText(values.front()); + return frame; + } + // -URL: depending on the number of values, use WXXX or TXXX (with description=URL) + if((key == "URL" || key.startsWith(urlPrefix)) && values.size() == 1){ + UserUrlLinkFrame *frame = UserUrlLinkFrame(String::UTF8); + frame->setDescription(key == "URL" ? key : key.substr(urlPrefix.size())); + frame->setUrl(values.front()); + return frame; + } + // -COMMENT: depending on the number of values, use COMM or TXXX (with description=COMMENT) + if((key == "COMMENT" || key.startsWith(commentPrefix)) && values.size() == 1){ + CommentsFrame *frame = CommentsFrame(String::UTF8); + frame->setDescription(key == "COMMENT" ? key : key.substr(commentPrefix.size())); + frame->setText(values.front()); + return frame; + } + // if non of the above cases apply, we use a TXXX frame with the key as description + return UserTextIdentificationFrame(key, values, String::UTF8); +} + Frame::~Frame() { delete d; @@ -263,7 +307,7 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc return checkEncoding(fields, encoding, header()->version()); } -static const uint frameTranslationSize = 50; +static const uint frameTranslationSize = 51; static const char *frameTranslation[][2] = { // Text information frames { "TALB", "ALBUM"}, @@ -325,7 +369,7 @@ static const char *frameTranslation[][2] = { { "WPUB", "PUBLISHERWEBPAGE" }, //{ "WXXX", "URL"}, handled specially // Other frames - //{ "COMM", "COMMENT" }, handled specially + { "COMM", "COMMENT" }, //{ "USLT", "LYRICS" }, handled specially }; @@ -399,6 +443,24 @@ PropertyMap Frame::asProperties() const return m; } } + +void Frame::splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, + PropertyMap &tiplProperties, PropertyMap &tmclProperties) +{ + + singleFrameProperties.clear(); + tiplProperties.clear(); + tmclProperties.clear(); + for(PropertyMap::ConstIterator it = original.begin(); it != original.end(); ++it) { + if(TextIdentificationFrame::involvedPeopleMap().contains(it->first)) + tiplProperties.insert(it->first, it->second); + else if(it->first.startsWith(TextIdentificationFrame::instrumentPrefix)) + tmclProperties.insert(it->first, it->second); + else + singleFrameProperties.insert(it->first, it->second); + } +} + //////////////////////////////////////////////////////////////////////////////// // Frame::Header class //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/mpeg/id3v2/id3v2frame.h b/taglib/mpeg/id3v2/id3v2frame.h index 8efe6870..3a9ade26 100644 --- a/taglib/mpeg/id3v2/id3v2frame.h +++ b/taglib/mpeg/id3v2/id3v2frame.h @@ -57,6 +57,14 @@ namespace TagLib { friend class FrameFactory; public: + + /*! + * Creates a textual frame which corresponds to a single key in the PropertyMap + * interface. These are all (User)TextIdentificationFrames except TIPL and TMCL, + * all (User)URLLinkFrames, CommentsFrames, and UnsynchronizedLyricsFrame. + */ + static Frame *createTextualFrame(const String &key, const StringList &values); + /*! * Destroys this Frame instance. */ @@ -127,6 +135,23 @@ namespace TagLib { */ static ByteVector textDelimiter(String::Type t); + /*! + * The string with which an instrument name is prefixed to build a key in a PropertyMap; + * used to translate PropertyMaps to TMCL frames. In the current implementation, this + * is "PERFORMER:". + */ + static const String instrumentPrefix; + /*! + * The PropertyMap key prefix which triggers the use of a COMM frame instead of a TXXX + * frame for a non-standard key. In the current implementation, this is "COMMENT:". + */ + static const String commentPrefix; + /*! + * The PropertyMap key prefix which triggers the use of a WXXX frame instead of a TXX + * frame for a non-standard key. In the current implementation, this is "URL:". + */ + static const String urlPrefix; + protected: class Header; @@ -244,6 +269,23 @@ namespace TagLib { */ static String frameIDToKey(const ByteVector &); + + /*! + * This helper function splits the PropertyMap \a original into three ProperytMaps + * \a singleFrameProperties, \a tiplProperties, and \a tmclProperties, such that: + * - \a singleFrameProperties contains only of keys which can be represented with + * exactly one ID3 frame per key. In the current implementation + * this is everything except for the fixed "involved people" keys and keys of the + * form "TextIdentificationFrame::instrumentPrefix" + "instrument", which are + * mapped to a TMCL frame. + * - \a tiplProperties will consist of those keys that are present in + * TextIdentificationFrame::involvedPeopleMap() + * - \a tmclProperties contains the "musician credits" keys which should be mapped + * to a TMCL frame + */ + static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, + PropertyMap &tiplProperties, PropertyMap &tmclProperties); + private: Frame(const Frame &); Frame &operator=(const Frame &); diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index f9b5dfa8..f6d7e772 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -344,160 +344,46 @@ PropertyMap ID3v2::Tag::properties() const PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps) { - FrameList toRemove; - PropertyMap properties = origProps; - // first find out what frames to remove; we do not remove in-place - // because that would invalidate FrameListMap iterators. - // At the moment, we remove _all_ frames that don't contain unsupported data, - // and create new ones in the next step; this is to avoid clumsy technicalities - // arising when trying to do this more efficient. For example, if the current tag - // contains one URL attribute stored in an WXXX frame, but the given \a properties - // contain two URL values, we would need to remove the WXXX frame (which supports - // only one value), and create a TXXX frame with description=URL. - // The same may happen with COMM and USLT. Additionally, handling of TIPL and TMCL is - // complicated. - // In the future, someone might come up with a more clever sync algorithm. :-) - for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it) { - String key = Frame::frameIDToKey(it->first); - // for unsupported (binary) frame types, as well as frames that need special treatment - // (TXXX, WXXX, COMM, TMCL, TIPL, USLT), key will be String::null - if(key.isNull()) - continue; - // else: non-user text or url frame -> there should be only one frame of this type, - // and it's asProperties() method should return a PropertyMap with exactly one key - // and empty unsupportedData(). - if(it->second.size() != 1) - debug("invalid ID3 tag: found more than one " + it->first + " frame"); - PropertyMap frameMap = it->second[0]->asProperties(); - if(properties.contains(key) && frameMap[key] == properties[key]) - properties.erase(key); - else - toRemove.append(it->second[0]); - } - - // now handle the special cases - // first: TXXX frames - FrameList &userTextFrames = frameList("TXXX"); - for(FrameList::ConstIterator it = userTextFrames.begin(); it != userTextFrames.end(); ++it) { - PropertyMap frameMap = (*it)->asProperties(); - if(!frameMap.unsupportedData().isEmpty()) - // don't touch unsupported frames - continue; - // TXXX frames yield only one key, so it must be begin()->first - String &key = frameMap.begin()->first; - if(!Frame::keyToFrameID(key).isNull()) - // TXXX frame which a description (=key) for which there is a dedicated frame. - // We don't want this, so remove the frame, the appropriate T*** or W*** frame - // will be created later on. - toRemove.append(*it); - if(key.find(":") > 0) - // colon-separated key: this should be inside a TMCL frame. - toRemove.append(*it); - // More (ugly) exceptions: If the user provides more than one COMMENT, LYRICS, or URL - // tag, we store all of these in a TXXX, because COMM, USLT and WXXX. Otherwise there - // should not be such a TXXX frame. - if(key == "COMMENT") { - if(properties.contains("COMMENT") - && properties["COMMENT"].size() >= 2 - && properties["COMMENT"] == frameMap.begin()->second) - properties.erase("COMMENT"); + FrameList framesToDelete; + // we split up the PropertyMap into the "normal" keys and the "complicated" ones, + // which are those according to TIPL or TMCL frames. + PropertyMap properties; + PropertyMap tiplProperties; + PropertyMap tmclProperties; + Frame::splitProperties(origProps, properties, tiplProperties, tmclProperties); + for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it){ + for(FrameList::ConstIterator lit = it->second.begin(); lit != it->second.end(); ++lit){ + PropertyMap frameProperties = (*lit)->asProperties(); + if(it->first == "TIPL") + if (tiplProperties != frameProperties) + framesToDelete.append(*lit); + else + tiplProperties.erase(frameProperties); + else if(it->first == "TMCL") + if (tmclProperties != frameProperties) + framesToDelete.append(*lit); + else + tmclProperties.erase(frameProperties); + else if(!properties.contains(frameProperties)) + framesToDelete.append(*lit); else - toRemove.append(*it); - }else if(key == "LYRICS") { - if(properties.contains("LYRICS") - && properties["LYRICS"].size() >= 2 - && properties["LYRICS"] == frameMap.begin()->second) - properties.erase("LYRICS"); - else - toRemove.append(*it); - }else if(key == "URL") { - if(properties.contains("URL") - && properties["URL"].size() >= 2 - && properties["URL"] == frameMap.begin()->second) - properties.erase("URL"); - else - toRemove.append(*it); + properties.erase(frameProperties); } } - - // next: WXXX frames - FrameList &userUrlFrames = frameList("WXXX"); - for(FrameList::ConstIterator it = userUrlFrames.begin(); it != userUrlFrames.end(); ++it) { - PropertyMap frameMap = (*it)->asProperties(); - if(!frameMap.unsupportedData().isEmpty()) - // don't touch unsupported frames - continue; - // WXXX frames yield only one key, so it must be begin()->first - String &key = frameMap.begin()->first; - if(!Frame::keyToFrameID(key).isNull()) - // WXXX frame which a description (=key) for which there is a dedicated frame. - // We don't want this, so remove the frame, the appropriate T*** or W*** frame - // will be created later on. - toRemove.append(*it); - else if(key.find(":") > 0) - // colon-separated key: this should be inside a TMCL frame. - toRemove.append(*it); - // More exceptions: we don't allow COMMENT and LYRICS in WXXX; they should be in COMM and USLT - // (or TXXX, see above). - else if(key == "COMMENT" || key == "LYRICS") - toRemove.append(*it); - // now, the key is either URL or some other string that neither has a dedicated text frame, nor - // a colon. We accept the frame if it's contents match the values in properties. However, if - // key != URL and the values are changed, they will be stored inside a TXXX frame instead, since - // we can't distinguish free-form text from free-form URL keys (possible fix: use URL:REASON like - // in TMCL / TIPL?). - else if(properties.contains(key) && properties[key] == frameMap.begin()->second) - properties.erase(key); - else - toRemove.append(*it); - } - for(FrameList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it) + for(FrameList::ConstIterator it = framesToDelete.begin(); it != framesToDelete.end(); ++it) removeFrame(*it); - // next: TIPL - PropertyMap existingTipl; - if(!frameList("TIPL").isEmpty()) - existingTipl = frameList("TIPL").front()->asProperties(); - PropertyMap requestedTipl; - KeyConversionMap::ConstIterator it = TextIdentificationFrame::involvedPeopleMap().begin(); - bool rebuildTipl = false; - for(; it != TextIdentificationFrame::involvedPeopleMap().end(); ++it) { - if(properties.contains(it->first)){ - requestedTipl.insert(it->first, properties[it->first]); - properties.erase(it->first); // it's ensured now that this key gets handled correctly - if(!existingTipl.contains(it->first) || existingTipl[it->first] != requestedTipl[it->first]) - rebuildTipl = true; - } else if(existingTipl.contains(it->first)) - rebuildTipl = true; - } - if(rebuildTipl){ - removeFrames("TIPL"); - addFrame(TextIdentificationFrame::createTIPLFrame(requestedTipl)); - } - - // next: create frames for everything still in properties except for TMCL ("PERFORMER:") - // keys, which are collected in a dedicated map - PropertyMap requestedTmcl; - for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ - if(it->first.find(":") != -1) - requestedTmcl.insert(it->first, it->second); - else{ - // phew. Now we are in the simple case that our key= pair can be represented by a - // single frame, either a T*** (not TIPL, TMCL) or W*** frame. - ByteVector id = Frame::keyToFrameID(it->first); - } - } - - // next: TMCL - PropertyMap existingTmcl; - if(!frameList("TMCL").isEmpty()) - existingTmcl = frameList("TMCL").front()->asProperties(); - bool rebuildTmcl = false; - // search for TMCL keys ("PERFORMER:") in properties - for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ - if(it->first.find(":") != -1) - requestedTmcl.insert(it->first, it->second); - } + // now create remaining frames: + // start with the involved people list (TIPL) + if(!tiplProperties.isEmpty()) + addFrame(TextIdentificationFrame::createTIPLFrame(tiplProperties)); + // proceed with the musician credit list (TMCL) + if(!tmclProperties.isEmpty()) + addFrame(TextIdentificationFrame::createTMCLFrame(tmclProperties)); + // now create the "one key per frame" frames + for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) + addFrame(Frame::createTextualFrame(it->first, it->second)); + return PropertyMap; // ID3 implements the complete PropertyMap interface, so an empty map is returned } ByteVector ID3v2::Tag::render() const diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index 437dabf0..3addbffa 100644 --- a/taglib/ogg/flac/oggflacfile.cpp +++ b/taglib/ogg/flac/oggflacfile.cpp @@ -92,16 +92,6 @@ Ogg::XiphComment *Ogg::FLAC::File::tag() const return d->comment; } -TagLib::TagDict Ogg::FLAC::File::toDict(void) const -{ - return d->comment->toDict(); -} - -void Ogg::FLAC::File::fromDict(const TagDict &dict) -{ - d->comment->fromDict(dict); -} - Properties *Ogg::FLAC::File::audioProperties() const { return d->properties; diff --git a/taglib/ogg/flac/oggflacfile.h b/taglib/ogg/flac/oggflacfile.h index e39ac2cc..d4373795 100644 --- a/taglib/ogg/flac/oggflacfile.h +++ b/taglib/ogg/flac/oggflacfile.h @@ -89,18 +89,6 @@ namespace TagLib { */ virtual XiphComment *tag() const; - /*! - * Implements the unified tag dictionary interface -- export function. - * Returns the contents of the Ogg::XiphComment as TagDict. - */ - TagDict toDict() const; - - /*! - * Implements the unified tag dictionary interface -- import function. - * Matches the TagDict's contents to the XiphComment of the file. - */ - void fromDict(const TagDict &); - /*! * Returns the FLAC::Properties for this file. If no audio properties * were read then this will return a null pointer. diff --git a/taglib/ogg/speex/speexfile.cpp b/taglib/ogg/speex/speexfile.cpp index d602bcc8..3a4940a2 100644 --- a/taglib/ogg/speex/speexfile.cpp +++ b/taglib/ogg/speex/speexfile.cpp @@ -82,16 +82,6 @@ Ogg::XiphComment *Speex::File::tag() const return d->comment; } -TagLib::TagDict Ogg::Speex::File::toDict(void) const -{ - return d->comment->toDict(); -} - -void Ogg::Speex::File::fromDict(const TagDict &dict) -{ - d->comment->fromDict(dict); -} - Speex::Properties *Speex::File::audioProperties() const { return d->properties; diff --git a/taglib/ogg/speex/speexfile.h b/taglib/ogg/speex/speexfile.h index 2af6cd82..c14cf2aa 100644 --- a/taglib/ogg/speex/speexfile.h +++ b/taglib/ogg/speex/speexfile.h @@ -82,17 +82,6 @@ namespace TagLib { * TagLib::File::tag(). */ virtual Ogg::XiphComment *tag() const; - /*! - * Implements the unified tag dictionary interface -- export function. - * Returns the contents of the Ogg::XiphComment as TagDict. - */ - TagDict toDict() const; - - /*! - * Implements the unified tag dictionary interface -- import function. - * Matches the TagDict's contents to the XiphComment of the file. - */ - void fromDict(const TagDict &); /*! * Returns the Speex::Properties for this file. If no audio properties diff --git a/taglib/ogg/vorbis/vorbisfile.cpp b/taglib/ogg/vorbis/vorbisfile.cpp index fe50d6d0..9b12f496 100644 --- a/taglib/ogg/vorbis/vorbisfile.cpp +++ b/taglib/ogg/vorbis/vorbisfile.cpp @@ -85,14 +85,14 @@ Ogg::XiphComment *Vorbis::File::tag() const return d->comment; } -TagLib::TagDict Ogg::Vorbis::File::toDict(void) const +PropertyMap Vorbis::File::properties() const { - return d->comment->toDict(); + return d->comment->properties(); } -void Ogg::Vorbis::File::fromDict(const TagDict &dict) +PropertyMap Vorbis::File::setProperties(const PropertyMap &properties) { - d->comment->fromDict(dict); + return d->comment->setProperties(properties); } Vorbis::Properties *Vorbis::File::audioProperties() const diff --git a/taglib/ogg/vorbis/vorbisfile.h b/taglib/ogg/vorbis/vorbisfile.h index 989eac3d..15c29d99 100644 --- a/taglib/ogg/vorbis/vorbisfile.h +++ b/taglib/ogg/vorbis/vorbisfile.h @@ -90,17 +90,19 @@ namespace TagLib { */ virtual Ogg::XiphComment *tag() const; + /*! - * Implements the unified tag dictionary interface -- export function. - * Returns the contents of the Ogg::XiphComment as TagDict. + * Implements the unified property interface -- export function. + * This forwards directly to XiphComment::properties(). */ - TagDict toDict() const; + PropertyMap properties() const; /*! * Implements the unified tag dictionary interface -- import function. - * Matches the TagDict's contents to the XiphComment of the file. + * Like properties(), this is a forwarder to the file's XiphComment. */ - void fromDict(const TagDict &); + PropertyMap setProperties(const PropertyMap &); + /*! * Returns the Vorbis::Properties for this file. If no audio properties * were read then this will return a null pointer. diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index 5a00b807..bc2a8569 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -84,15 +84,14 @@ ID3v2::Tag *RIFF::AIFF::File::tag() const return d->tag; } -TagLib::TagDict RIFF::AIFF::File::toDict(void) const +PropertyMap RIFF::AIFF::File::properties() const { - return d->tag->toDict(); - + return d->tag->properties(); } -void RIFF::AIFF::File::fromDict(const TagDict &dict) +PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties) { - d->tag->fromDict(dict); + return d->tag->setProperties(properties); } diff --git a/taglib/riff/aiff/aifffile.h b/taglib/riff/aiff/aifffile.h index af7d7b7a..a50c8ecb 100644 --- a/taglib/riff/aiff/aifffile.h +++ b/taglib/riff/aiff/aifffile.h @@ -84,16 +84,16 @@ namespace TagLib { virtual ID3v2::Tag *tag() const; /*! - * Implements the unified tag dictionary interface -- export function. - * This method forwards to ID3v2::Tag::toDict. + * Implements the unified property interface -- export function. + * This method forwards to ID3v2::Tag::properties(). */ - TagDict toDict() const; + PropertyMap properties() const; /*! - * Implements the unified tag dictionary interface -- import function. - * This method forwards to ID3v2::Tag::fromDict. + * Implements the unified property interface -- import function. + * This method forwards to ID3v2::Tag::setProperties(). */ - void fromDict(const TagDict &); + PropertyMap setProperties(const PropertyMap &); /*! * Returns the AIFF::Properties for this file. If no audio properties diff --git a/taglib/riff/wav/wavfile.cpp b/taglib/riff/wav/wavfile.cpp index cb274dd1..afc307d8 100644 --- a/taglib/riff/wav/wavfile.cpp +++ b/taglib/riff/wav/wavfile.cpp @@ -84,14 +84,14 @@ ID3v2::Tag *RIFF::WAV::File::tag() const return d->tag; } -TagLib::TagDict RIFF::WAV::File::toDict(void) const +PropertyMap RIFF::WAV::File::properties() const { - return d->tag->toDict(); + return d->tag->properties(); } -void RIFF::WAV::File::fromDict(const TagDict &dict) +PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) { - d->tag->fromDict(dict); + return d->tag->setProperties(properties); } diff --git a/taglib/riff/wav/wavfile.h b/taglib/riff/wav/wavfile.h index 8e75afdb..861f3f77 100644 --- a/taglib/riff/wav/wavfile.h +++ b/taglib/riff/wav/wavfile.h @@ -84,16 +84,16 @@ namespace TagLib { virtual ID3v2::Tag *tag() const; /*! - * Implements the unified tag dictionary interface -- export function. - * This method forwards to ID3v2::Tag::toDict. + * Implements the unified property interface -- export function. + * This method forwards to ID3v2::Tag::properties(). */ - TagDict toDict() const; + PropertyMap properties() const; /*! - * Implements the unified tag dictionary interface -- import function. - * This method forwards to ID3v2::Tag::fromDict. + * Implements the unified property interface -- import function. + * This method forwards to ID3v2::Tag::setProperties(). */ - void fromDict(const TagDict &); + PropertyMap setProperties(const PropertyMap &); /*! * Returns the WAV::Properties for this file. If no audio properties diff --git a/taglib/toolkit/tpropertymap.h b/taglib/toolkit/tpropertymap.h index 1fbcb584..071c3e9b 100644 --- a/taglib/toolkit/tpropertymap.h +++ b/taglib/toolkit/tpropertymap.h @@ -91,11 +91,22 @@ namespace TagLib { */ bool contains(const String &key) const; + /*! + * Returns true if this map contains all keys of \a other + * and the values coincide for that keys. + */ + bool contains(const PropertyMap &other) const; + /*! * Erase the \a key and its values from the map. */ PropertyMap &erase(const String &key); + /*! + * Erases from this map all keys that appear in \a other. + */ + PropertyMap &erase(const PropertyMap &other); + /*! * Merge the contents of \a other into this PropertyMap. * If a key is contained in both maps, the values of the second