mirror of
https://github.com/taglib/taglib.git
synced 2025-06-03 09:08:09 -04:00
Splitted ID3v2Tag::toDict() into several functions.
This should simplify future transition to virtual functions.
This commit is contained in:
parent
0356249368
commit
2d31075047
@ -25,6 +25,35 @@
|
||||
#include "tdebug.h"
|
||||
#include "id3v2dicttools.h"
|
||||
#include "tmap.h"
|
||||
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
#include "frames/urllinkframe.h"
|
||||
#include "frames/uniquefileidentifierframe.h"
|
||||
#include "frames/unsynchronizedlyricsframe.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
namespace TagLib {
|
||||
namespace ID3v2 {
|
||||
|
||||
@ -110,16 +139,9 @@ namespace TagLib {
|
||||
"UFID", // unique file identifier
|
||||
};
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
String frameIDToTagName(const ByteVector &id) {
|
||||
String frameIDToTagName(const ByteVector &id)
|
||||
{
|
||||
static Map<ByteVector, String> m;
|
||||
if (m.isEmpty())
|
||||
for (size_t i = 0; i < numid3frames; ++i)
|
||||
@ -133,7 +155,8 @@ namespace TagLib {
|
||||
return "UNKNOWNID3TAG"; //TODO: implement this nicer
|
||||
}
|
||||
|
||||
ByteVector tagNameToFrameID(const String &s) {
|
||||
ByteVector tagNameToFrameID(const String &s)
|
||||
{
|
||||
static Map<String, ByteVector> m;
|
||||
if (m.isEmpty())
|
||||
for (size_t i = 0; i < numid3frames; ++i)
|
||||
@ -143,7 +166,8 @@ namespace TagLib {
|
||||
return "TXXX";
|
||||
}
|
||||
|
||||
bool isIgnored(const ByteVector& id) {
|
||||
bool isIgnored(const ByteVector& id)
|
||||
{
|
||||
List<ByteVector> ignoredList;
|
||||
if (ignoredList.isEmpty())
|
||||
for (uint i = 0; i < ignoredFramesSize; ++i)
|
||||
@ -151,16 +175,106 @@ namespace TagLib {
|
||||
return ignoredList.contains(id);
|
||||
}
|
||||
|
||||
FrameIDMap deprecationMap() {
|
||||
static FrameIDMap depMap;
|
||||
if (depMap.isEmpty())
|
||||
for(uint i = 0; i < deprecatedFramesSize; ++i)
|
||||
depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1];
|
||||
return depMap;
|
||||
|
||||
|
||||
bool isDeprecated(const ByteVector& id)
|
||||
{
|
||||
return deprecationMap().contains(id);
|
||||
}
|
||||
|
||||
bool isDeprecated(const ByteVector& id) {
|
||||
return deprecationMap().contains(id);
|
||||
/*
|
||||
* The following _parseXXX functions are to be replaced by implementations of a virtual
|
||||
* function in ID3v2::Frame ASAP.
|
||||
*/
|
||||
KeyValuePair _parseUserTextIdentificationFrame(const UserTextIdentificationFrame *frame)
|
||||
{
|
||||
String tagName = frame->description();
|
||||
StringList l(frame->fieldList());
|
||||
// this is done because taglib stores the description also as first entry
|
||||
// in the field list. (why?)
|
||||
if (l.contains(tagName))
|
||||
l.erase(l.find(tagName));
|
||||
// handle user text frames set by the QuodLibet / exFalso package,
|
||||
// which sets the description to QuodLibet::<tagName> instead of simply
|
||||
// <tagName>.
|
||||
int pos = tagName.find("::");
|
||||
tagName = (pos != -1) ? tagName.substr(pos+2) : tagName;
|
||||
return KeyValuePair(tagName.upper(), l);
|
||||
}
|
||||
|
||||
KeyValuePair _parseTextIdentificationFrame(const TextIdentificationFrame *frame)
|
||||
{
|
||||
String tagName = frameIDToTagName(frame->frameID());
|
||||
StringList l = frame->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 lit = l.begin(); lit != l.end(); ++lit) {
|
||||
bool ok = false;
|
||||
int test = lit->toInt(&ok); // test if the genre value is an integer
|
||||
if (ok)
|
||||
*lit = ID3v1::genre(test);
|
||||
}
|
||||
}
|
||||
else if (tagName == "DATE") {
|
||||
for (StringList::Iterator lit = l.begin(); lit != l.end(); ++lit) {
|
||||
// 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 = lit->find("T");
|
||||
if (tpos != -1)
|
||||
(*lit)[tpos] = ' ';
|
||||
}
|
||||
}
|
||||
return KeyValuePair(tagName, l);
|
||||
}
|
||||
|
||||
KeyValuePair _parseUserUrlLinkFrame(const UserUrlLinkFrame *frame)
|
||||
{
|
||||
String tagName = frame->description().upper();
|
||||
if (tagName == "")
|
||||
tagName = "URL";
|
||||
return KeyValuePair(tagName, frame->url());
|
||||
}
|
||||
|
||||
KeyValuePair _parseUrlLinkFrame(const UrlLinkFrame *frame)
|
||||
{
|
||||
return KeyValuePair(frameIDToTagName(frame->frameID()) , frame->url());
|
||||
}
|
||||
|
||||
KeyValuePair _parseCommentsFrame(const CommentsFrame *frame)
|
||||
{
|
||||
String tagName = frame->description().upper();
|
||||
if (tagName.isEmpty())
|
||||
tagName = "COMMENT";
|
||||
return KeyValuePair(tagName, frame->text());
|
||||
}
|
||||
|
||||
KeyValuePair _parseUnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame *frame)
|
||||
{
|
||||
return KeyValuePair("LYRICS", frame->text());
|
||||
}
|
||||
|
||||
KeyValuePair parseFrame(const Frame *frame)
|
||||
{
|
||||
const ByteVector &id = frame->frameID();
|
||||
if (id == "TXXX")
|
||||
return _parseUserTextIdentificationFrame(dynamic_cast< const UserTextIdentificationFrame* >(frame));
|
||||
else if (id[0] == 'T')
|
||||
return _parseTextIdentificationFrame(dynamic_cast<const TextIdentificationFrame* >(frame));
|
||||
else if (id == "WXXX")
|
||||
return _parseUserUrlLinkFrame(dynamic_cast< const UserUrlLinkFrame* >(frame));
|
||||
else if (id[0] == 'W')
|
||||
return _parseUrlLinkFrame(dynamic_cast< const UrlLinkFrame* >(frame));
|
||||
else if (id == "COMM")
|
||||
return _parseCommentsFrame(dynamic_cast< const CommentsFrame* >(frame));
|
||||
else if (id == "USLT")
|
||||
return _parseUnsynchronizedLyricsFrame(dynamic_cast< const UnsynchronizedLyricsFrame* >(frame));
|
||||
else {
|
||||
debug("parsing unknown ID3 frame: " + id);
|
||||
return KeyValuePair("UNKNOWNID3TAG", frame->toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "tstringlist.h"
|
||||
#include "taglib_export.h"
|
||||
#include "tmap.h"
|
||||
#include <utility>
|
||||
|
||||
namespace TagLib {
|
||||
namespace ID3v2 {
|
||||
@ -36,18 +37,38 @@ namespace TagLib {
|
||||
* This file contains methods used by the unified dictionary interface for ID3v2 tags
|
||||
* (tag name conversion, handling of un-translatable frameIDs, ...).
|
||||
*/
|
||||
typedef Map<ByteVector, ByteVector> FrameIDMap;
|
||||
|
||||
typedef Map<ByteVector, ByteVector> FrameIDMap;
|
||||
typedef std::pair<String, StringList> KeyValuePair;
|
||||
|
||||
// forward declaration
|
||||
class Frame;
|
||||
/*!
|
||||
* Returns an appropriate ID3 frame ID for the given free-form tag name.
|
||||
*/
|
||||
ByteVector TAGLIB_EXPORT tagNameToFrameID(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.
|
||||
*/
|
||||
String TAGLIB_EXPORT frameIDToTagName(const ByteVector &);
|
||||
|
||||
/*!
|
||||
* Tell if the given frame ID is ignored by the unified dictionary subsystem. This is true
|
||||
* for frames that don't admit a textual representation, such as pictures or other binary
|
||||
* information.
|
||||
*/
|
||||
bool TAGLIB_EXPORT isIgnored(const ByteVector &);
|
||||
|
||||
FrameIDMap TAGLIB_EXPORT deprecationMap();
|
||||
|
||||
bool TAGLIB_EXPORT isDeprecated(const ByteVector&);
|
||||
|
||||
/*!
|
||||
* Parse the ID3v2::Frame *Frame* to a pair of a human-readable key (e.g. ARTIST) and
|
||||
* a StringList containing the values.
|
||||
*/
|
||||
KeyValuePair parseFrame(const Frame*);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -340,92 +340,16 @@ TagDict ID3v2::Tag::toDict() const
|
||||
for (; frameIt != frameList().end(); ++frameIt) {
|
||||
ByteVector id = (*frameIt)->frameID();
|
||||
|
||||
if (isIgnored(id)) {
|
||||
debug("found ignored id3 frame " + id);
|
||||
continue;
|
||||
if (isIgnored(id))
|
||||
debug("toDict() found ignored id3 frame: " + id);
|
||||
else if (isDeprecated(id))
|
||||
debug("toDict() found deprecated id3 frame: " + id);
|
||||
else {
|
||||
// in the future, something like dict[frame->tagName()].append(frame->values())
|
||||
// might replace the following lines.
|
||||
KeyValuePair kvp = parseFrame(*frameIt);
|
||||
dict[kvp.first].append(kvp.second);
|
||||
}
|
||||
if (isDeprecated(id)) {
|
||||
debug("found deprecated id3 frame " + id);
|
||||
continue;
|
||||
}
|
||||
if (id[0] == 'T') {
|
||||
if (id == "TXXX") {
|
||||
const UserTextIdentificationFrame *uframe
|
||||
= dynamic_cast< const UserTextIdentificationFrame* >(*frameIt);
|
||||
String tagName = uframe->description();
|
||||
StringList l(uframe->fieldList());
|
||||
// this is done because taglib stores the description also as first entry
|
||||
// in the field list. (why?)
|
||||
//
|
||||
if (l.contains(tagName))
|
||||
l.erase(l.find(tagName));
|
||||
// handle user text frames set by the QuodLibet / exFalso package,
|
||||
// which sets the description to QuodLibet::<tagName> instead of simply
|
||||
// <tagName>.
|
||||
int pos = tagName.find("::");
|
||||
tagName = (pos != -1) ? tagName.substr(pos+2) : tagName;
|
||||
dict[tagName.upper()].append(l);
|
||||
}
|
||||
else {
|
||||
const TextIdentificationFrame* tframe
|
||||
= dynamic_cast< const TextIdentificationFrame* >(*frameIt);
|
||||
String tagName = frameIDToTagName(id);
|
||||
StringList l = tframe->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 lit = l.begin(); lit != l.end(); ++lit) {
|
||||
bool ok = false;
|
||||
int test = lit->toInt(&ok); // test if the genre value is an integer
|
||||
if (ok) {
|
||||
*lit = ID3v1::genre(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tagName == "DATE") {
|
||||
for (StringList::Iterator lit = l.begin(); lit != l.end(); ++lit) {
|
||||
// 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 = lit->find("T");
|
||||
if (tpos != -1)
|
||||
(*lit)[tpos] = ' ';
|
||||
}
|
||||
}
|
||||
dict[tagName].append(l);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (id[0] == 'W') {
|
||||
if (id == "WXXX") {
|
||||
const UserUrlLinkFrame *uframe = dynamic_cast< const UserUrlLinkFrame* >(*frameIt);
|
||||
String tagname = uframe->description().upper();
|
||||
if (tagname == "")
|
||||
tagname = "URL";
|
||||
dict[tagname].append(uframe->url());
|
||||
}
|
||||
else {
|
||||
const UrlLinkFrame* uframe = dynamic_cast< const UrlLinkFrame* >(*frameIt);
|
||||
dict[frameIDToTagName(id)].append(uframe->url());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (id == "COMM") {
|
||||
const CommentsFrame *cframe = dynamic_cast< const CommentsFrame* >(*frameIt);
|
||||
String tagName = cframe->description().upper();
|
||||
if (tagName.isEmpty())
|
||||
tagName = "COMMENT";
|
||||
dict[tagName].append(cframe->text());
|
||||
continue;
|
||||
}
|
||||
if (id == "USLT") {
|
||||
const UnsynchronizedLyricsFrame *uframe
|
||||
= dynamic_cast< const UnsynchronizedLyricsFrame* >(*frameIt);
|
||||
dict["LYRICS"].append(uframe->text());
|
||||
continue;
|
||||
}
|
||||
debug("unknown frame ID: " + id);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
@ -437,15 +361,21 @@ void ID3v2::Tag::fromDict(const TagDict &dict)
|
||||
// because that would invalidate FrameListMap iterators.
|
||||
//
|
||||
for (FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it) {
|
||||
if (it->second.size() == 0) // ignore empty map entries (does this ever happen?)
|
||||
// ignore empty map entries (does this ever happen?)
|
||||
if (it->second.size() == 0)
|
||||
continue;
|
||||
if (isDeprecated(it->first))// automatically remove deprecated frames
|
||||
|
||||
// automatically remove deprecated frames
|
||||
else if (isDeprecated(it->first))
|
||||
toRemove.append(it->second);
|
||||
else if (it->first == "TXXX") { // handle user text frames specially
|
||||
for (FrameList::ConstIterator fit = it->second.begin(); fit != it->second.end(); ++fit) {
|
||||
UserTextIdentificationFrame* frame
|
||||
= dynamic_cast< UserTextIdentificationFrame* >(*fit);
|
||||
String tagName = frame->description();
|
||||
// handle user text frames set by the QuodLibet / exFalso package,
|
||||
// which sets the description to QuodLibet::<tagName> instead of simply
|
||||
// <tagName>.
|
||||
int pos = tagName.find("::");
|
||||
tagName = (pos == -1) ? tagName : tagName.substr(pos+2);
|
||||
if (!dict.contains(tagName.upper()))
|
||||
|
Loading…
x
Reference in New Issue
Block a user