mirror of
https://github.com/taglib/taglib.git
synced 2025-06-03 09:08:09 -04:00
Started to work on ID3v2.
This commit is contained in:
parent
e4d955d6ef
commit
a5e45f196b
@ -113,27 +113,34 @@ TagLib::Tag *MPC::File::tag() const
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
TagLib::TagDict MPC::File::toDict(void) const
|
||||
PropertyMap MPC::File::properties() const
|
||||
{
|
||||
// once Tag::toDict() is virtual, this case distinction could actually be done
|
||||
// within TagUnion.
|
||||
if (d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(APEIndex, false)->toDict();
|
||||
if (d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->toDict();
|
||||
return TagLib::TagDict();
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(APEIndex, false)->properties();
|
||||
if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->properties();
|
||||
return PropertyMap();
|
||||
}
|
||||
|
||||
void MPC::File::fromDict(const TagDict &dict)
|
||||
void MPC::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
if (d->hasAPE)
|
||||
d->tag.access<APE::Tag>(APEIndex, false)->fromDict(dict);
|
||||
else if (d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(ID3v1Index, false)->fromDict(dict);
|
||||
else
|
||||
d->tag.access<APE::Tag>(APEIndex, true)->fromDict(dict);
|
||||
if(d->hasAPE)
|
||||
d->tag.access<APE::Tag>(APEIndex, false)->removeUnsupportedProperties(properties);
|
||||
if(d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(ID3v1Index, false)->removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap MPC::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(APEIndex, false)->setProperties(properties);
|
||||
else if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->setProperties(properties);
|
||||
else
|
||||
return d->tag.access<APE::Tag>(APE, true)->setProperties(properties);
|
||||
}
|
||||
|
||||
|
||||
MPC::Properties *MPC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
|
@ -109,18 +109,20 @@ namespace TagLib {
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only the APE
|
||||
* tag will be converted to the TagDict.
|
||||
* tag will be converted to the PropertyMap.
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* Implements the unified property interface -- import function.
|
||||
* As with the export, only one tag is taken into account. If the file
|
||||
* has no tag at all, APE will be created.
|
||||
* has no tag at all, an APE tag will be created.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the MPC::Properties for this file. If no audio properties
|
||||
|
@ -238,6 +238,28 @@ void UserTextIdentificationFrame::setDescription(const String &s)
|
||||
TextIdentificationFrame::setText(l);
|
||||
}
|
||||
|
||||
PropertyMap UserTextIdentificationFrame::asProperties() const
|
||||
{
|
||||
String tagName = description();
|
||||
StringList l(fieldList());
|
||||
// this is done because taglib stores the description also as first entry
|
||||
// in the field list. (why?)
|
||||
StringList::Iterator tagIt = l.find(tagName);
|
||||
if(tagIt != l.end())
|
||||
l.erase(tagIt);
|
||||
// Quodlibet/Exfalso use QuodLibet::<tagname> if you set an arbitrary ID3
|
||||
// tag.
|
||||
int pos = tagName.find("::");
|
||||
tagName = (pos != -1) ? tagName.substr(pos+2).upper() : tagName.upper();
|
||||
PropertyMap map;
|
||||
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("TXXX/" + description());
|
||||
else
|
||||
map.insert(key, l);
|
||||
return map;
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
||||
ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
|
@ -236,6 +236,11 @@ namespace TagLib {
|
||||
void setText(const String &text);
|
||||
void setText(const StringList &fields);
|
||||
|
||||
/*!
|
||||
* Reimplement function.
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Searches for the user defined text frame with the description \a description
|
||||
* in \a tag. This returns null if no matching frames were found.
|
||||
|
@ -262,6 +262,142 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc
|
||||
return checkEncoding(fields, encoding, header()->version());
|
||||
}
|
||||
|
||||
static const uint frameTranslationSize = 55;
|
||||
static const char *frameTranslation[][2] = {
|
||||
// Text information frames
|
||||
{ "TALB", "ALBUM"},
|
||||
{ "TBPM", "BPM" },
|
||||
{ "TCOM", "COMPOSER" },
|
||||
{ "TCON", "GENRE" },
|
||||
{ "TCOP", "COPYRIGHT" },
|
||||
{ "TDEN", "ENCODINGTIME" },
|
||||
{ "TDLY", "PLAYLISTDELAY" },
|
||||
{ "TDOR", "ORIGINALDATE" },
|
||||
{ "TDRC", "DATE" },
|
||||
// { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
{ "TDRL", "RELEASEDATE" },
|
||||
{ "TDTG", "TAGGINGDATE" },
|
||||
{ "TENC", "ENCODEDBY" },
|
||||
{ "TEXT", "LYRICIST" },
|
||||
{ "TFLT", "FILETYPE" },
|
||||
{ "TIPL", "INVOLVEDPEOPLE" },
|
||||
{ "TIT1", "CONTENTGROUP" },
|
||||
{ "TIT2", "TITLE"},
|
||||
{ "TIT3", "SUBTITLE" },
|
||||
{ "TKEY", "INITIALKEY" },
|
||||
{ "TLAN", "LANGUAGE" },
|
||||
{ "TLEN", "LENGTH" },
|
||||
{ "TMCL", "MUSICIANCREDITS" },
|
||||
{ "TMED", "MEDIATYPE" },
|
||||
{ "TMOO", "MOOD" },
|
||||
{ "TOAL", "ORIGINALALBUM" },
|
||||
{ "TOFN", "ORIGINALFILENAME" },
|
||||
{ "TOLY", "ORIGINALLYRICIST" },
|
||||
{ "TOPE", "ORIGINALARTIST" },
|
||||
{ "TOWN", "OWNER" },
|
||||
{ "TPE1", "ARTIST"},
|
||||
{ "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST'
|
||||
{ "TPE3", "CONDUCTOR" },
|
||||
{ "TPE4", "REMIXER" }, // could also be ARRANGER
|
||||
{ "TPOS", "DISCNUMBER" },
|
||||
{ "TPRO", "PRODUCEDNOTICE" },
|
||||
{ "TPUB", "PUBLISHER" },
|
||||
{ "TRCK", "TRACKNUMBER" },
|
||||
{ "TRSN", "RADIOSTATION" },
|
||||
{ "TRSO", "RADIOSTATIONOWNER" },
|
||||
{ "TSOA", "ALBUMSORT" },
|
||||
{ "TSOP", "ARTISTSORT" },
|
||||
{ "TSOT", "TITLESORT" },
|
||||
{ "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes
|
||||
{ "TSRC", "ISRC" },
|
||||
{ "TSSE", "ENCODING" },
|
||||
// URL frames
|
||||
{ "WCOP", "COPYRIGHTURL" },
|
||||
{ "WOAF", "FILEWEBPAGE" },
|
||||
{ "WOAR", "ARTISTWEBPAGE" },
|
||||
{ "WOAS", "AUDIOSOURCEWEBPAGE" },
|
||||
{ "WORS", "RADIOSTATIONWEBPAGE" },
|
||||
{ "WPAY", "PAYMENTWEBPAGE" },
|
||||
{ "WPUB", "PUBLISHERWEBPAGE" },
|
||||
{ "WXXX", "URL"},
|
||||
// Other frames
|
||||
{ "COMM", "COMMENT" },
|
||||
{ "USLT", "LYRICS" },
|
||||
};
|
||||
|
||||
Map<ByteVector, String> &idMap()
|
||||
{
|
||||
static Map<ByteVector, String> m;
|
||||
if(m.isEmpty())
|
||||
for(size_t i = 0; i < frameTranslationSize; ++i)
|
||||
m[frameTranslation[i][0]] = frameTranslation[i][1];
|
||||
return m;
|
||||
}
|
||||
|
||||
// list of deprecated frames and their successors
|
||||
static const uint deprecatedFramesSize = 4;
|
||||
static const char *deprecatedFrames[][2] = {
|
||||
{"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
|
||||
{"TDAT", "TDRC"}, // 2.3 -> 2.4
|
||||
{"TYER", "TDRC"}, // 2.3 -> 2.4
|
||||
{"TIME", "TDRC"}, // 2.3 -> 2.4
|
||||
};
|
||||
|
||||
FrameIDMap &deprecationMap()
|
||||
{
|
||||
static FrameIDMap depMap;
|
||||
if(depMap.isEmpty())
|
||||
for(uint i = 0; i < deprecatedFramesSize; ++i)
|
||||
depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1];
|
||||
return depMap;
|
||||
}
|
||||
|
||||
String Frame::frameIDToKey(const ByteVector &id)
|
||||
{
|
||||
Map<ByteVector, String> &m = idMap();
|
||||
if(m.contains(id))
|
||||
return m[id];
|
||||
if(deprecationMap().contains(id))
|
||||
return m[deprecationMap()[id]];
|
||||
return String::null;
|
||||
}
|
||||
|
||||
ByteVector Frame::keyToFrameID(const String &s)
|
||||
{
|
||||
static Map<String, ByteVector> m;
|
||||
if(m.isEmpty())
|
||||
for(size_t i = 0; i < frameTranslationSize; ++i)
|
||||
m[frameTranslation[i][1]] = frameTranslation[i][0];
|
||||
if(m.contains(s.upper()))
|
||||
return m[s];
|
||||
return ByteVector::null;
|
||||
}
|
||||
|
||||
PropertyMap Frame::asProperties() const
|
||||
{
|
||||
const ByteVector &id = frameID();
|
||||
// workaround until this function is virtual
|
||||
if(id == "TXXX")
|
||||
return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties();
|
||||
else if(id[0] == 'T')
|
||||
return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties();
|
||||
else if(id == "WXXX")
|
||||
return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties();
|
||||
else if(id[0] == 'W')
|
||||
return dynamic_cast< const UrlLinkFrame* >(this)->asProperties();
|
||||
else if(id == "COMM")
|
||||
return dynamic_cast< const CommentsFrame* >(this)->asProperties();
|
||||
else if(id == "USLT")
|
||||
return dynamic_cast< const UnsynchronizedLyricsFrame* >(this)->asProperties();
|
||||
else {
|
||||
PropertyMap m;
|
||||
m.unsupportedData().append(id);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Frame::Header class
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -222,6 +222,27 @@ namespace TagLib {
|
||||
String::Type checkTextEncoding(const StringList &fields,
|
||||
String::Type encoding) const;
|
||||
|
||||
|
||||
/*!
|
||||
* Parses the contents of this frame as PropertyMap. If that fails, the returend
|
||||
* PropertyMap will be empty, and its unsupportedData() will contain this frame's
|
||||
* ID.
|
||||
* BIC: Will be a virtual function in future releases.
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Returns an appropriate ID3 frame ID for the given free-form tag key. This method
|
||||
* will return ByteVector::null if no specialized translation is found.
|
||||
*/
|
||||
static ByteVector keyToFrameID(const String &);
|
||||
|
||||
/*!
|
||||
* Returns a free-form tag name for the given ID3 frame ID. Note that this does not work
|
||||
* for general frame IDs such as TXXX or WXXX; in such a case String::null is returned.
|
||||
*/
|
||||
static String frameIDToKey(const ByteVector &);
|
||||
|
||||
private:
|
||||
Frame(const Frame &);
|
||||
Frame &operator=(const Frame &);
|
||||
|
@ -31,17 +31,9 @@
|
||||
#include "id3v2extendedheader.h"
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2synchdata.h"
|
||||
#include "id3v2dicttools.h"
|
||||
#include "tbytevector.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
#include "frames/urllinkframe.h"
|
||||
#include "frames/uniquefileidentifierframe.h"
|
||||
#include "frames/unsynchronizedlyricsframe.h"
|
||||
#include "frames/unknownframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
@ -334,25 +326,19 @@ void ID3v2::Tag::removeFrames(const ByteVector &id)
|
||||
removeFrame(*it, true);
|
||||
}
|
||||
|
||||
TagDict ID3v2::Tag::toDict(StringList *ignoreInfo) const
|
||||
PropertyMap ID3v2::Tag::properties() const
|
||||
{
|
||||
TagDict dict;
|
||||
FrameList::ConstIterator frameIt = frameList().begin();
|
||||
for (; frameIt != frameList().end(); ++frameIt) {
|
||||
ByteVector id = (*frameIt)->frameID();
|
||||
|
||||
PropertyMap properties;
|
||||
for(FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) {
|
||||
ByteVector id = (*it)->frameID();
|
||||
if (ignored(id)) {
|
||||
debug("toDict() found ignored id3 frame: " + id);
|
||||
if (ignoreInfo)
|
||||
ignoreInfo->append(String(id) + " frame is not supported");
|
||||
} else if (deprecated(id)) {
|
||||
debug("toDict() found deprecated id3 frame: " + id);
|
||||
if (ignoreInfo)
|
||||
ignoreInfo->append(String(id) + " frame is deprecated");
|
||||
} else {
|
||||
// in the future, something like dict[frame->tagName()].append(frame->values())
|
||||
// might replace the following lines.
|
||||
KeyValuePair kvp = parseFrame(*frameIt);
|
||||
KeyValuePair kvp = parseFrame(*it);
|
||||
dict[kvp.first].append(kvp.second);
|
||||
}
|
||||
}
|
||||
|
@ -261,22 +261,26 @@ namespace TagLib {
|
||||
void removeFrames(const ByteVector &id);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* Implements the unified property interface -- export function.
|
||||
* This function does some work to translate the hard-specified ID3v2
|
||||
* frame types into a free-form string-to-stringlist dictionary.
|
||||
* frame types into a free-form string-to-stringlist PropertyMap.
|
||||
*
|
||||
* If the optional pointer to a StringList is given, that list will
|
||||
* be filled with a descriptive text for each ID3v2 frame that could
|
||||
* not be incorporated into the dict interface (binary data, unsupported
|
||||
* frames, ...).
|
||||
*/
|
||||
TagDict toDict(StringList *ignoredInfo = 0) const;
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* See the comments in toDict().
|
||||
* Removes unsupported frames given by \a properties. The elements of
|
||||
* \a properties must be taken from properties().unsupportedData() and
|
||||
* are the four-byte frame IDs of ID3 frames which are not compatible
|
||||
* with the PropertyMap schema.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* See the comments in properties().
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Render the tag back to binary data, suitable to be written to disk.
|
||||
|
@ -133,29 +133,38 @@ TagLib::Tag *MPEG::File::tag() const
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
TagLib::TagDict MPEG::File::toDict(void) const
|
||||
PropertyMap MPEG::File::properties() const
|
||||
{
|
||||
// once Tag::toDict() is virtual, this case distinction could actually be done
|
||||
// once Tag::properties() is virtual, this case distinction could actually be done
|
||||
// within TagUnion.
|
||||
if (d->hasID3v2)
|
||||
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->toDict();
|
||||
if (d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(APEIndex, false)->toDict();
|
||||
if (d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->toDict();
|
||||
return TagLib::TagDict();
|
||||
if(d->hasID3v2)
|
||||
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(APEIndex, false)->properties();
|
||||
if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->properties();
|
||||
return PropertyMap();
|
||||
}
|
||||
|
||||
void MPEG::File::fromDict(const TagDict &dict)
|
||||
void MPEG::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
if (d->hasID3v2)
|
||||
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->fromDict(dict);
|
||||
else if (d->hasAPE)
|
||||
d->tag.access<APE::Tag>(APEIndex, false)->fromDict(dict);
|
||||
else if (d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(ID3v1Index, false)->fromDict(dict);
|
||||
if(d->hasID3v2)
|
||||
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(properties);
|
||||
else if(d->hasAPE)
|
||||
d->tag.access<APE::Tag>(APEIndex, false)->removeUnsupportedProperties(properties);
|
||||
else if(d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(ID3v1Index, false)->removeUnsupportedProperties(properties);
|
||||
}
|
||||
PropertyMap MPEG::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(d->hasID3v2)
|
||||
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->setProperties(properties);
|
||||
else if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(APEIndex, false)->setProperties(properties);
|
||||
else if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->setProperties(properties);
|
||||
else
|
||||
d->tag.access<ID3v2::Tag>(ID3v2Index, true)->fromDict(dict);
|
||||
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
|
||||
}
|
||||
|
||||
MPEG::Properties *MPEG::File::audioProperties() const
|
||||
|
@ -130,19 +130,21 @@ namespace TagLib {
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* If the file contains more than one tag (e.g. ID3v2 and v1), only the
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains more than one tag, only the
|
||||
* first one (in the order ID3v2, APE, ID3v1) will be converted to the
|
||||
* TagDict.
|
||||
* PropertyMap.
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* As with the export, only one tag is taken into account. If the file
|
||||
* has no tag at all, ID3v2 will be created.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the MPEG::Properties for this file. If no audio properties
|
||||
|
@ -23,13 +23,12 @@
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
typedef Map<String,StringList> supertype;
|
||||
|
||||
PropertyMap::PropertyMap() : Map<String,StringList>()
|
||||
PropertyMap::PropertyMap() : SimplePropertyMap()
|
||||
{
|
||||
}
|
||||
|
||||
PropertyMap::PropertyMap(const PropertyMap &m) : Map<String,StringList>(m)
|
||||
PropertyMap::PropertyMap(const PropertyMap &m) : SimplePropertyMap(m)
|
||||
{
|
||||
}
|
||||
|
||||
@ -43,11 +42,11 @@ bool PropertyMap::insert(const String &key, const StringList &values)
|
||||
if(realKey.isNull())
|
||||
return false;
|
||||
|
||||
Iterator result = supertype::find(realKey);
|
||||
Iterator result = SimplePropertyMap::find(realKey);
|
||||
if(result == end())
|
||||
supertype::insert(realKey, values);
|
||||
SimplePropertyMap::insert(realKey, values);
|
||||
else
|
||||
supertype::operator[](realKey).append(values);
|
||||
SimplePropertyMap::operator[](realKey).append(values);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -56,8 +55,8 @@ bool PropertyMap::replace(const String &key, const StringList &values)
|
||||
String realKey = prepareKey(key);
|
||||
if(realKey.isNull())
|
||||
return false;
|
||||
supertype::erase(realKey);
|
||||
supertype::insert(realKey, values);
|
||||
SimplePropertyMap::erase(realKey);
|
||||
SimplePropertyMap::insert(realKey, values);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -66,7 +65,7 @@ PropertyMap::Iterator PropertyMap::find(const String &key)
|
||||
String realKey = prepareKey(key);
|
||||
if(realKey.isNull())
|
||||
return end();
|
||||
return supertype::find(realKey);
|
||||
return SimplePropertyMap::find(realKey);
|
||||
}
|
||||
|
||||
PropertyMap::ConstIterator PropertyMap::find(const String &key) const
|
||||
@ -74,40 +73,46 @@ PropertyMap::ConstIterator PropertyMap::find(const String &key) const
|
||||
String realKey = prepareKey(key);
|
||||
if(realKey.isNull())
|
||||
return end();
|
||||
return supertype::find(realKey);
|
||||
return SimplePropertyMap::find(realKey);
|
||||
}
|
||||
|
||||
bool PropertyMap::contains(const String &key) const
|
||||
{
|
||||
String realKey = prepareKey(key);
|
||||
// we consider keys with empty value list as not present
|
||||
if(realKey.isNull() || supertype::operator[](realKey).isEmpty())
|
||||
if(realKey.isNull() || SimplePropertyMap::operator[](realKey).isEmpty())
|
||||
return false;
|
||||
return supertype::contains(realKey);
|
||||
return SimplePropertyMap::contains(realKey);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Erase the \a key and its values from the map.
|
||||
*/
|
||||
PropertyMap &PropertyMap::erase(const String &key)
|
||||
{
|
||||
String realKey = prepareKey(key);
|
||||
if (realKey.isNull())
|
||||
if(realKey.isNull())
|
||||
return *this;
|
||||
supertype::erase(realKey);
|
||||
SimplePropertyMap::erase(realKey);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertyMap &PropertyMap::merge(const PropertyMap &other)
|
||||
{
|
||||
for(PropertyMap::ConstIterator it = other.begin(); it != other.end(); ++it) {
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
unsupported.append(other.unsupported);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const StringList &PropertyMap::operator[](const String &key) const
|
||||
{
|
||||
String realKey = prepareKey(key);
|
||||
return supertype::operator[](realKey);
|
||||
return SimplePropertyMap::operator[](realKey);
|
||||
}
|
||||
|
||||
StringList &PropertyMap::operator[](const String &key)
|
||||
{
|
||||
String realKey = prepareKey(key);
|
||||
return supertype::operator[](realKey);
|
||||
return SimplePropertyMap::operator[](realKey);
|
||||
}
|
||||
|
||||
void PropertyMap::removeEmpty()
|
||||
@ -125,6 +130,11 @@ StringList &PropertyMap::unsupportedData()
|
||||
return unsupported;
|
||||
}
|
||||
|
||||
const StringList &PropertyMap::unsupportedData() const
|
||||
{
|
||||
return unsupported;
|
||||
}
|
||||
|
||||
static String PropertyMap::prepareKey(const String &proposed) {
|
||||
if(proposed.isEmpty())
|
||||
return String::null;
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
typedef Map<String,StringList> SimplePropertyMap;
|
||||
|
||||
//! A map for format-independent <key,valuelist> tag representations.
|
||||
|
||||
@ -46,12 +47,12 @@ namespace TagLib {
|
||||
*
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT PropertyMap: public Map<String,StringList>
|
||||
class TAGLIB_EXPORT PropertyMap: public SimplePropertyMap
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Map<String,StringList>::Iterator Iterator;
|
||||
typedef Map<String,StringList>::ConstIterator ConstIterator;
|
||||
typedef SimplePropertyMap::Iterator Iterator;
|
||||
typedef SimplePropertyMap::ConstIterator ConstIterator;
|
||||
|
||||
PropertyMap();
|
||||
|
||||
@ -95,6 +96,14 @@ namespace TagLib {
|
||||
*/
|
||||
PropertyMap &erase(const String &key);
|
||||
|
||||
/*!
|
||||
* Merge the contents of \a other into this PropertyMap.
|
||||
* If a key is contained in both maps, the values of the second
|
||||
* are appended to that of the first.
|
||||
* The unsupportedData() lists are concatenated as well.
|
||||
*/
|
||||
PropertyMap &merge(const PropertyMap &other);
|
||||
|
||||
/*!
|
||||
* Returns a reference to the value associated with \a key.
|
||||
*
|
||||
@ -121,6 +130,7 @@ namespace TagLib {
|
||||
* same PropertyMap as argument.
|
||||
*/
|
||||
StringList &unsupportedData();
|
||||
const StringList &unsupportedData() const;
|
||||
|
||||
/*!
|
||||
* Removes all entries which have an empty value list.
|
||||
|
Loading…
x
Reference in New Issue
Block a user