Migration to new PropertyMap ... done ape to mod.

This commit is contained in:
Michael Helmling
2012-01-21 14:52:24 +01:00
parent 18ae797df4
commit e4d955d6ef
18 changed files with 398 additions and 234 deletions

View File

@ -109,23 +109,31 @@ TagLib::Tag *APE::File::tag() const
return &d->tag;
}
TagLib::TagDict APE::File::toDict(void) const
PropertyMap APE::File::properties() const
{
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 APE::File::fromDict(const TagDict &dict)
void APE::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);
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 APE::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
d->tag.access<APE::Tag>(APE, true)->fromDict(dict);
return d->tag.access<APE::Tag>(APE, true)->setProperties(properties);
}
APE::Properties *APE::File::audioProperties() const

View File

@ -111,18 +111,24 @@ 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 APE
* will be converted to the TagDict.
* will be converted to the PropertyMap.
*/
TagDict toDict() const;
PropertyMap properties() const;
/*!
* Implements the unified tag dictionary interface -- import function.
* Removes unsupported properties. Forwards to the actual Tag's
* removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* As for the export, only one tag is taken into account. If the file
* has no tag at all, APE will be created.
*/
void fromDict(const TagDict &);
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the APE::Properties for this file. If no audio properties
* were read then this will return a null pointer.

View File

@ -174,61 +174,73 @@ void APE::Tag::setTrack(uint i)
addValue("TRACK", String::number(i), true);
}
TagDict APE::Tag::toDict() const
// conversions of tag keys between what we use in PropertyMap and what's usual
// for APE tags
static const uint keyConversionsSize = 5; //usual, APE
static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
{"DATE", "YEAR" },
{"ALBUMARTIST", "ALBUM ARTIST"},
{"DISCNUMBER", "DISC" },
{"REMIXER", "MIXARTIST" }};
PropertyMap APE::Tag::properties() const
{
TagDict dict;
PropertyMap properties;
ItemListMap::ConstIterator it = itemListMap().begin();
for (; it != itemListMap().end(); ++it) {
String tagName = it->first.upper();
// These two tags need to be handled specially; in APE tags the track number is usually
// named TRACK instead of TRACKNUMBER, the date tag is YEAR instead of DATE
//
if (tagName == "TRACK")
tagName = "TRACKNUMBER";
else if (tagName == "YEAR")
tagName = "DATE";
else if (tagName == "ALBUM ARTIST")
tagName = "ALBUMARTIST";
if (it->second.type() == Item::Text)
dict[tagName].append(it->second.toStringList());
for(; it != itemListMap().end(); ++it) {
String tagName = PropertyMap::prepareKey(it->first);
// if the item is Binary or Locator, or if the key is an invalid string,
// add to unsupportedData
if(it->second.type() != Item::Text || tagName.isNull())
properties.unsupportedData().append(it->first);
else {
// Some tags need to be handled specially
for(uint i = 0; i < keyConversionsSize; ++i)
if(tagName == keyConversions[i][1])
tagName = keyConversions[i][0];
properties[tagName].append(it->second.toStringList());
}
}
return dict;
return properties;
}
void APE::Tag::fromDict(const TagDict &origDict)
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
{
TagDict dict(origDict); // make a local copy that can be modified
StringList::ConstIterator it = properties.begin();
for(; it != properties.end(); ++it)
removeItem(*it);
}
// see comment in toDict() about TRACKNUMBER and YEAR
if (dict.contains("TRACKNUMBER")) {
dict.insert("TRACK", dict["TRACKNUMBER"]);
dict.erase("TRACKNUMBER");
}
if (dict.contains("DATE")) {
dict.insert("YEAR", dict["DATE"]);
dict.erase("DATE");
}
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap properties(origProps); // make a local copy that can be modified
// see comment in properties()
for(uint i = 0; i < keyConversionsSize; ++i)
if(properties.contains(keyConversions[i][0])) {
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
properties.erase(keyConversions[i][0]);
}
// first check if tags need to be removed completely
StringList toRemove;
ItemListMap::ConstIterator remIt = itemListMap().begin();
for (; remIt != itemListMap().end(); ++remIt) {
if (remIt->second.type() != APE::Item::Text)
// ignore binary and locator APE items
continue;
if (!dict.contains(remIt->first.upper()))
for(; remIt != itemListMap().end(); ++remIt) {
String key = PropertyMap::prepareKey(remIt->first);
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
toRemove.append(remIt->first);
}
for (StringList::Iterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
removeItem(*removeIt);
// now sync in the "forward direction
TagDict::ConstIterator it = dict.begin();
for (; it != dict.end(); ++it) {
// now sync in the "forward direction"
PropertyMap::ConstIterator it = properties.begin();
for(; it != properties.end(); ++it) {
const String &tagName = it->first;
if (!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
if (it->second.size() == 0)
if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
if(it->second.size() == 0)
removeItem(tagName);
else {
StringList::ConstIterator valueIt = it->second.begin();
@ -239,6 +251,7 @@ void APE::Tag::fromDict(const TagDict &origDict)
}
}
}
return PropertyMap;
}
APE::Footer *APE::Tag::footer() const

View File

@ -107,20 +107,25 @@ namespace TagLib {
* Implements the unified tag dictionary interface -- export function.
* APE tags are perfectly compatible with the dictionary interface because they
* support both arbitrary tag names and multiple values. Currently only
* APE items of type *Text* are handled by the dictionary interface, while
* *Binary* and *Locator* items are simply ignored.
* APE items of type *Text* are handled by the dictionary interface; all *Binary*
* and *Locator* items will be put into the unsupportedData list and can be
* deleted on request using removeUnsupportedProperties(). The same happens
* to Text items if their key is invalid for PropertyMap (which should actually
* never happen).
*
* The only conversion done by this export function is to rename the APE tags
* TRACK to TRACKNUMBER and YEAR to DATE, respectively, in order to be compliant
* with the names used in other formats.
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively,
* in order to be compliant with the names used in other formats.
*/
TagDict toDict() const;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified tag dictionary interface -- import function. The same
* comments as for the export function apply.
*/
void fromDict(const TagDict &);
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns a pointer to the tag's footer.