Skip to content

Commit

Permalink
Implemented asProperties() in all relevant textual frames.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Helmling committed Jan 22, 2012
1 parent a5e45f1 commit 0c8e5bb
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 50 deletions.
2 changes: 0 additions & 2 deletions taglib/CMakeLists.txt
Expand Up @@ -55,7 +55,6 @@ set(tag_HDRS
mpeg/xingheader.h
mpeg/id3v1/id3v1tag.h
mpeg/id3v1/id3v1genres.h
mpeg/id3v2/id3v2dicttools.h
mpeg/id3v2/id3v2extendedheader.h
mpeg/id3v2/id3v2frame.h
mpeg/id3v2/id3v2header.h
Expand Down Expand Up @@ -139,7 +138,6 @@ set(id3v1_SRCS
)

set(id3v2_SRCS
mpeg/id3v2/id3v2dicttools.cpp
mpeg/id3v2/id3v2framefactory.cpp
mpeg/id3v2/id3v2synchdata.cpp
mpeg/id3v2/id3v2tag.cpp
Expand Down
13 changes: 13 additions & 0 deletions taglib/mpeg/id3v2/frames/commentsframe.cpp
Expand Up @@ -109,6 +109,19 @@ void CommentsFrame::setTextEncoding(String::Type encoding)
d->textEncoding = encoding;
}

PropertyMap CommentsFrame::asDescription() const
{
String key = PropertyMap::prepareKey(description());
PropertyMap map;
if(key.isEmpty())
key = "COMMENT";
if(key.isNull())
map.unsupportedData().append(L"COMM/" + description());
else
map.insert(key, text());
return map;
}

CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
{
ID3v2::FrameList comments = tag->frameList("COMM");
Expand Down
11 changes: 11 additions & 0 deletions taglib/mpeg/id3v2/frames/commentsframe.h
Expand Up @@ -136,6 +136,17 @@ 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"
* - 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.
* - The single value will be the frame's text().
*/
PropertyMap asDescription() const;

/*!
* Comments each have a unique description. This searches for a comment
* frame with the decription \a d and returns a pointer to it. If no
Expand Down
106 changes: 96 additions & 10 deletions taglib/mpeg/id3v2/frames/textidentificationframe.cpp
Expand Up @@ -92,6 +92,40 @@ void TextIdentificationFrame::setTextEncoding(String::Type encoding)
d->textEncoding = encoding;
}

PropertyMap TextIdentificationFrame::asProperties() const
{
if(frameID() == "TIPL")
return makeTIPLProperties();
if(frameID() == "TMCL")
return makeTMCLProperties();
PropertyMap map;
String tagName = frameIDToTagName(frameID());
if(tagName.isNull()) {
map.unsupportedData().append(frameID());
return map;
}
StringList values = fieldList();
if(tagName == "GENRE") {
// Special case: Support ID3v1-style genre numbers. They are not officially supported in
// ID3v2, however it seems that still a lot of programs use them.
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
bool ok = false;
int test = it->toInt(&ok); // test if the genre value is an integer
if(ok)
*it = ID3v1::genre(test);
}
} else if(tagName == "DATE") {
for (StringList::Iterator it = values.begin(); it != values.end(); ++it) {
// ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time.
// Since this is unusual in other formats, the T is removed.
int tpos = it->find("T");
if (tpos != -1)
(*it)[tpos] = ' ';
}
}
return KeyValuePair(tagName, values);
}

////////////////////////////////////////////////////////////////////////////////
// TextIdentificationFrame protected members
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -170,6 +204,63 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header
parseFields(fieldData(data));
}

// array of allowed TIPL prefixes and their corresponding key value
static const uint involvedPeopleSize = 5;
static const char* involvedPeople[2] = {
{"ARRANGER", "ARRANGER"},
{"ENGINEER", "ENGINEER"},
{"PRODUCER", "PRODUCER"},
{"DJ-MIX", "DJMIXER"},
{"MIX", "MIXER"}
};

PropertyMap TextIdentificationFrame::makeTIPLProperties() const
{
PropertyMap map;
if(fieldList().size() % 2 != 0){
// according to the ID3 spec, TIPL must contain an even number of entries
map.unsupportedData().append(frameID());
return map;
}
for(StringList::ConstIterator it = fieldList().begin(); it != fieldList().end(); ++it) {
bool found = false;
for(uint i = 0; i < involvedPeopleSize; ++i)
if(*it == involvedPeople[i][0]) {
map.insert(involvedPeople[i][1], (++it).split(","));
found = true;
break;
}
if(!found){
// invalid involved role -> mark whole frame as unsupported in order to be consisten with writing
map.clear();
map.unsupportedData().append(frameID());
return map;
}
}
return map;
}

PropertyMap TextIdentificationFrame::makeTMCLProperties() const
{
PropertyMap map;
if(fieldList().size() % 2 != 0){
// according to the ID3 spec, TMCL must contain an even number of entries
map.unsupportedData().append(frameID());
return map;
}
for(StringList::ConstIterator it = fieldList().begin(); it != fieldList().end(); ++it) {
String key = PropertyMap::prepareKey(*it);
if(key.isNull()) {
// instrument is not a valid key -> frame unsupported
map.clear();
map.unsupportedData().append(frameID());
return map;
}
map.insert(key, (++it).split(","));
}
return map;
}

////////////////////////////////////////////////////////////////////////////////
// UserTextIdentificationFrame public members
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -241,22 +332,17 @@ void UserTextIdentificationFrame::setDescription(const String &s)
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.
// 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());
map.unsupportedData().append(L"TXXX/" + description());
else
map.insert(key, l);
for(StringList::ConstIterator it = fieldList().begin(); it != fieldList().end(); ++it)
if(*it != description())
map.insert(key, *it);
return map;
}

Expand Down
24 changes: 23 additions & 1 deletion taglib/mpeg/id3v2/frames/textidentificationframe.h
Expand Up @@ -173,6 +173,8 @@ namespace TagLib {
*/
StringList fieldList() const;

PropertyMap asProperties() const;

protected:
// Reimplementations.

Expand All @@ -188,6 +190,16 @@ namespace TagLib {
TextIdentificationFrame(const TextIdentificationFrame &);
TextIdentificationFrame &operator=(const TextIdentificationFrame &);

/*!
* Parses the special structure of a TIPL frame
* Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
* "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
*/
PropertyMap makeTIPLProperties() const;
/*!
* Parses the special structure of a TMCL frame.
*/
PropertyMap makeTMCLProperties() const;
class TextIdentificationFramePrivate;
TextIdentificationFramePrivate *d;
};
Expand Down Expand Up @@ -237,7 +249,17 @@ namespace TagLib {
void setText(const StringList &fields);

/*!
* Reimplement function.
* A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
* - the key is the frame's description, uppercased
* - if the description contains '::', only the substring after that
* separator is considered as key (compatibility with exfalso)
* - if the above rules don't yield a valid key (e.g. containing non-ASCII
* characters), the returned map will contain an entry "TXXX/<description>"
* in its unsupportedData() list.
* - The values will be copies of the fieldList().
* - If the description() appears as value in fieldList(), it will be omitted
* in the value list, in order to be compatible with TagLib which copies
* the description() into the fieldList().
*/
PropertyMap asProperties() const;

Expand Down
7 changes: 7 additions & 0 deletions taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
Expand Up @@ -111,6 +111,13 @@ void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
d->textEncoding = encoding;
}

PropertyMap UnsynchronizedLyricsFrame::asProperties() const
{
PropertyMap map;
map.insert("LYRICS", text());
return map;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
Expand Down
7 changes: 7 additions & 0 deletions taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h
Expand Up @@ -134,6 +134,13 @@ namespace TagLib {
*/
void setTextEncoding(String::Type encoding);


/*!
* Parses this frame as PropertyMap. The returned map will contain a single key
* "LYRICS" with the text() as single value.
*/
PropertyMap asProperties() const;

protected:
// Reimplementations.

Expand Down
25 changes: 25 additions & 0 deletions taglib/mpeg/id3v2/frames/urllinkframe.cpp
Expand Up @@ -78,6 +78,18 @@ String UrlLinkFrame::toString() const
return url();
}

PropertyMap UrlLinkFrame::asProperties() const
{
String key = frameIDToKey(frameID());
PropertyMap map;
if(key.isNull())
// unknown W*** frame - this normally shouldn't happen
map.unsupportedData().append(frameID());
else
map.insert(key, url());
return map;
}

void UrlLinkFrame::parseFields(const ByteVector &data)
{
d->url = String(data);
Expand Down Expand Up @@ -139,6 +151,19 @@ void UserUrlLinkFrame::setDescription(const String &s)
d->description = s;
}

PropertyMap UserUrlLinkFrame::asProperties() const
{
String key = PropertyMap::prepareKey(description());
PropertyMap map;
if(key.isEmpty())
key = "URL";
if(key.isNull())
map.unsupportedData().append(L"WXXX/" + description());
else
map.insert(key, url());
return map;
}

void UserUrlLinkFrame::parseFields(const ByteVector &data)
{
if(data.size() < 2) {
Expand Down
11 changes: 11 additions & 0 deletions taglib/mpeg/id3v2/frames/urllinkframe.h
Expand Up @@ -68,6 +68,7 @@ namespace TagLib {

virtual void setText(const String &s);
virtual String toString() const;
PropertyMap asProperties() const;

protected:
virtual void parseFields(const ByteVector &data);
Expand Down Expand Up @@ -150,6 +151,16 @@ namespace TagLib {
*/
void setDescription(const String &s);

/*!
* Parses the UserUrlLinkFrame as PropertyMap. The description() is taken as key,
* and the URL as single value.
* - if description() is empty, the key will be "URL".
* - otherwise, if description() is not a valid key (e.g. containing non-ASCII
* characters), the returned map will contain an entry "WXXX/<description>"
* in its unsupportedData() list.
*/
PropertyMap asProperties() const;

protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
Expand Down
7 changes: 4 additions & 3 deletions taglib/mpeg/id3v2/id3v2frame.cpp
Expand Up @@ -38,6 +38,7 @@

#include "id3v2frame.h"
#include "id3v2synchdata.h"
#include "tpropertymap.h"

using namespace TagLib;
using namespace ID3v2;
Expand Down Expand Up @@ -262,7 +263,7 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc
return checkEncoding(fields, encoding, header()->version());
}

static const uint frameTranslationSize = 55;
static const uint frameTranslationSize = 53;
static const char *frameTranslation[][2] = {
// Text information frames
{ "TALB", "ALBUM"},
Expand All @@ -283,14 +284,14 @@ static const char *frameTranslation[][2] = {
{ "TENC", "ENCODEDBY" },
{ "TEXT", "LYRICIST" },
{ "TFLT", "FILETYPE" },
{ "TIPL", "INVOLVEDPEOPLE" },
//{ "TIPL", "INVOLVEDPEOPLE" }, handled separately
{ "TIT1", "CONTENTGROUP" },
{ "TIT2", "TITLE"},
{ "TIT3", "SUBTITLE" },
{ "TKEY", "INITIALKEY" },
{ "TLAN", "LANGUAGE" },
{ "TLEN", "LENGTH" },
{ "TMCL", "MUSICIANCREDITS" },
//{ "TMCL", "MUSICIANCREDITS" }, handled separately
{ "TMED", "MEDIATYPE" },
{ "TMOO", "MOOD" },
{ "TOAL", "ORIGINALALBUM" },
Expand Down
1 change: 1 addition & 0 deletions taglib/mpeg/id3v2/id3v2frame.h
Expand Up @@ -33,6 +33,7 @@
namespace TagLib {

class StringList;
class PropertyMap;

namespace ID3v2 {

Expand Down

0 comments on commit 0c8e5bb

Please sign in to comment.