ID3 interface complete; vorbis done; wav done

This commit is contained in:
Michael Helmling
2012-02-14 21:27:14 +01:00
parent a8632f710f
commit d2c43d7174
21 changed files with 238 additions and 233 deletions

View File

@@ -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;
}

View File

@@ -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/<description>" in the unsupportedData()
* attribute of the returned map.
* - otherwise, the key will be "COMMENT:<description>"
* - 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

View File

@@ -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;

View File

@@ -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;
/*!

View File

@@ -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;
}

View File

@@ -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/<description>" in the unsupportedData()
* attribute of the returned map.
* - otherwise, the key will be "LYRICS:<description>"
* - 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:

View File

@@ -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;
}

View File

@@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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 &);

View File

@@ -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:<instrument>")
// 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=<value list> 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:<instrument>") 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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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