]> granicus.if.org Git - taglib/commitdiff
Splitted ID3v2Tag::toDict() into several functions.
authorMichael Helmling <helmling@mathematik.uni-kl.de>
Sun, 11 Sep 2011 16:22:15 +0000 (18:22 +0200)
committerMichael Helmling <helmling@mathematik.uni-kl.de>
Sun, 11 Sep 2011 16:22:15 +0000 (18:22 +0200)
This should simplify future transition to virtual functions.

taglib/mpeg/id3v2/id3v2dicttools.cpp
taglib/mpeg/id3v2/id3v2dicttools.h
taglib/mpeg/id3v2/id3v2tag.cpp

index 903c93724d705536670da6123a2868ab39ff710b..9fef9ad0a779239bd9d6300ea25d145ef1dd930e 100644 (file)
 #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) {
+
+    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());
+      }
+    }
   }
 }
index 3e7a329fdd60357d055c77f6f9e3462a22f9f304..7dfdda2f448320aa6136f280fe8554fcfaacc2b4 100644 (file)
@@ -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 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*);
+
 
   }
 }
index 83406cdb1e6f58fb8de2a723501712a472d1b948..29dce9ad44aef7267eba3732f2e31a642beb2dd2 100644 (file)
@@ -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 (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 (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 (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()))