]> granicus.if.org Git - taglib/commitdiff
Implement the PropertyMap interface for WMA
authorLukáš Lalinský <lalinsky@gmail.com>
Fri, 23 Nov 2012 08:32:00 +0000 (09:32 +0100)
committerLukáš Lalinský <lalinsky@gmail.com>
Fri, 23 Nov 2012 08:32:00 +0000 (09:32 +0100)
taglib/asf/asffile.cpp
taglib/asf/asffile.h
taglib/asf/asftag.cpp
taglib/asf/asftag.h
taglib/mpeg/id3v2/id3v2frame.cpp
taglib/toolkit/tfile.cpp
taglib/toolkit/tpropertymap.h
tests/test_asf.cpp

index 96b8706ff6f63c463014a1f8475bde95099e0b99..eb0009249844d77c1b655bcc3a15ed8a62d9f636 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <tdebug.h>
 #include <tbytevectorlist.h>
+#include <tpropertymap.h>
 #include <tstring.h>
 #include "asffile.h"
 #include "asftag.h"
@@ -403,6 +404,21 @@ ASF::Tag *ASF::File::tag() const
   return d->tag;
 }
 
+PropertyMap ASF::File::properties() const
+{
+  return d->tag->properties();
+}
+
+void ASF::File::removeUnsupportedProperties(const StringList &properties)
+{
+  d->tag->removeUnsupportedProperties(properties);
+}
+
+PropertyMap ASF::File::setProperties(const PropertyMap &properties)
+{
+  return d->tag->setProperties(properties);
+}
+
 ASF::Properties *ASF::File::audioProperties() const
 {
   return d->properties;
index 3a7eef565eddcd84f05fdc5b7303a7f04c167d26..7d0e3bc7991d8e9a77013d14eb5b3ba00805156c 100644 (file)
@@ -90,6 +90,22 @@ namespace TagLib {
        */
       virtual Tag *tag() const;
 
+      /*!
+       * Implements the unified property interface -- export function.
+       */
+      PropertyMap properties() const;
+
+      /*!
+       * Removes unsupported properties. Forwards to the actual Tag's
+       * removeUnsupportedProperties() function.
+       */
+      void removeUnsupportedProperties(const StringList &properties);
+
+      /*!
+       * Implements the unified property interface -- import function.
+       */
+      PropertyMap setProperties(const PropertyMap &);
+
       /*!
        * Returns the ASF audio properties for this file.
        */
index b7b541fcbe493cb156f4bb825f253baa3acfebf6..1cbd16eb553300af16014f5bf809335b9b490c77 100644 (file)
@@ -27,6 +27,7 @@
 #include <config.h>
 #endif
 
+#include <tpropertymap.h>
 #include "asftag.h"
 
 using namespace TagLib;
@@ -196,3 +197,162 @@ bool ASF::Tag::isEmpty() const
          d->attributeListMap.isEmpty();
 }
 
+static const char *keyTranslation[][2] = {
+  { "WM/AlbumTitle", "ALBUM" },
+  { "WM/Composer", "COMPOSER" },
+  { "WM/Writer", "WRITER" },
+  { "WM/Conductor", "CONDUCTOR" },
+  { "WM/ModifiedBy", "REMIXER" },
+  { "WM/Year", "DATE" },
+  { "WM/OriginalReleaseYear", "ORIGINALDATE" },
+  { "WM/Producer", "PRODUCER" },
+  { "WM/ContentGroupDescription", "GROUPING" },
+  { "WM/SubTitle", "SUBTITLE" },
+  { "WM/SetSubTitle", "DISCSUBTITLE" },
+  { "WM/TrackNumber", "TRACKNUMBER" },
+  { "WM/PartOfSet", "DISCNUMBER" },
+  { "WM/Genre", "GENRE" },
+  { "WM/BeatsPerMinute", "BPM" },
+  { "WM/Mood", "MOOD" },
+  { "WM/ISRC", "ISRC" },
+  { "WM/Lyrics", "LYRICS" },
+  { "WM/Media", "MEDIA" },
+  { "WM/Publisher", "LABEL" },
+  { "WM/CatalogNo", "CATALOGNUMBER" },
+  { "WM/Barcode", "BARCODE" },
+  { "WM/EncodedBy", "ENCODEDBY" },
+  { "WM/AlbumSortOrder", "ALBUMSORT" },
+  { "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
+  { "WM/ArtistSortOrder", "ARTISTSORT" },
+  { "WM/TitleSortOrder", "TITLESORT" },
+  { "WM/Script", "SCRIPT" },
+  { "WM/Language", "LANGUAGE" },
+  { "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
+  { "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
+  { "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
+  { "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
+  { "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
+  { "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
+  { "MusicIP/PUID", "MUSICIP_PUID" },
+  { "Acoustid/Id", "ACOUSTID_ID" },
+  { "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
+};
+
+PropertyMap ASF::Tag::properties() const
+{
+  static Map<String, String> keyMap;
+  if(keyMap.isEmpty()) {
+    int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
+    for(int i = 0; i < numKeys; i++) {
+      keyMap[keyTranslation[i][0]] = keyTranslation[i][1];
+    }
+  }
+
+  PropertyMap props;
+
+  if(!d->title.isEmpty()) {
+    props["TITLE"] = d->title;
+  }
+  if(!d->artist.isEmpty()) {
+    props["ARTIST"] = d->artist;
+  }
+  if(!d->copyright.isEmpty()) {
+    props["COPYRIGHT"] = d->copyright;
+  }
+  if(!d->comment.isEmpty()) {
+    props["COMMENT"] = d->comment;
+  }
+
+  ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin();
+  for(; it != d->attributeListMap.end(); ++it) {
+    if(keyMap.contains(it->first)) {
+      String key = keyMap[it->first];
+      AttributeList::ConstIterator it2 = it->second.begin();
+      for(; it2 != it->second.end(); ++it2) {
+        if(key == "TRACKNUMBER") {
+          if(it2->type() == ASF::Attribute::DWordType)
+            props.insert(key, String::number(it2->toUInt()));
+          else
+            props.insert(key, it2->toString());
+        }
+        else {
+          props.insert(key, it2->toString());
+        }
+      }
+    }
+    else {
+      props.unsupportedData().append(it->first);
+    }
+  }
+  return props;
+}
+
+void ASF::Tag::removeUnsupportedProperties(const StringList &props)
+{
+  StringList::ConstIterator it = props.begin();
+  for(; it != props.end(); ++it)
+    d->attributeListMap.erase(*it);
+}
+
+PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
+{
+  static Map<String, String> reverseKeyMap;
+  if(reverseKeyMap.isEmpty()) {
+    int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
+    for(int i = 0; i < numKeys; i++) {
+      reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
+    }
+  }
+
+  PropertyMap origProps = properties();
+  PropertyMap::ConstIterator it = origProps.begin();
+  for(; it != origProps.end(); ++it) {
+    if(!props.contains(it->first) || props[it->first].isEmpty()) {
+      if(it->first == "TITLE") {
+        d->title = String::null;
+      }
+      else if(it->first == "ARTIST") {
+        d->artist = String::null;
+      }
+      else if(it->first == "COMMENT") {
+        d->comment = String::null;
+      }
+      else if(it->first == "COPYRIGHT") {
+        d->copyright = String::null;
+      }
+      else {
+        d->attributeListMap.erase(reverseKeyMap[it->first]);
+      }
+    }
+  }
+
+  PropertyMap ignoredProps;
+  it = props.begin();
+  for(; it != props.end(); ++it) {
+    if(reverseKeyMap.contains(it->first)) {
+      String name = reverseKeyMap[it->first];
+      removeItem(name);
+      StringList::ConstIterator it2 = it->second.begin();
+      for(; it2 != it->second.end(); ++it2) {
+        addAttribute(name, *it2);
+      }
+    }
+    else if(it->first == "TITLE") {
+      d->title = it->second.toString();
+    }
+    else if(it->first == "ARTIST") {
+      d->artist = it->second.toString();
+    }
+    else if(it->first == "COMMENT") {
+      d->comment = it->second.toString();
+    }
+    else if(it->first == "COPYRIGHT") {
+      d->copyright = it->second.toString();
+    }
+    else {
+      ignoredProps.insert(it->first, it->second);
+    }
+  }
+
+  return ignoredProps;
+}
index 6b2d2bf35925547dcd910ded4a61d0911f08a1d6..f68579d88ec4540db450791987907fcbf0c96073 100644 (file)
@@ -176,6 +176,10 @@ namespace TagLib {
        */
       void addAttribute(const String &name, const Attribute &attribute);
 
+      PropertyMap properties() const;
+      void removeUnsupportedProperties(const StringList& properties);
+      PropertyMap setProperties(const PropertyMap &properties);
+
     private:
 
       class TagPrivate;
index f94a074ef7ce60a6d3efab1373f75d21c28299d3..e2b84311d7ed3b1985ae24f91960acce82bce450 100644 (file)
@@ -368,7 +368,7 @@ static const char *frameTranslation[][2] = {
   { "TPE4", "REMIXER" }, // could also be ARRANGER
   { "TPOS", "DISCNUMBER" },
   { "TPRO", "PRODUCEDNOTICE" },
-  { "TPUB", "PUBLISHER" },
+  { "TPUB", "LABEL" },
   { "TRCK", "TRACKNUMBER" },
   { "TRSN", "RADIOSTATION" },
   { "TRSO", "RADIOSTATIONOWNER" },
index 2457949686449fe961bed3823ce801f6d1619a71..7251f3f703e8b78fe41ce28e4e69076f096b29fc 100644 (file)
@@ -155,9 +155,8 @@ PropertyMap File::properties() const
     return dynamic_cast<const XM::File* >(this)->properties();
   if(dynamic_cast<const MP4::File* >(this))
     return dynamic_cast<const MP4::File* >(this)->properties();
-  // no specialized implementation available -> use generic one
-  // - ASF: ugly format, largely undocumented, not worth implementing
-  //   dict interface ...
+  if(dynamic_cast<const ASF::File* >(this))
+    return dynamic_cast<const ASF::File* >(this)->properties();
   return tag()->properties();
 }
 
@@ -195,6 +194,8 @@ void File::removeUnsupportedProperties(const StringList &properties)
     dynamic_cast<XM::File* >(this)->removeUnsupportedProperties(properties);
   else if(dynamic_cast<MP4::File* >(this))
     dynamic_cast<MP4::File* >(this)->removeUnsupportedProperties(properties);
+  else if(dynamic_cast<ASF::File* >(this))
+    dynamic_cast<ASF::File* >(this)->removeUnsupportedProperties(properties);
   else
     tag()->removeUnsupportedProperties(properties);
 }
@@ -235,6 +236,8 @@ PropertyMap File::setProperties(const PropertyMap &properties)
     return dynamic_cast<XM::File* >(this)->setProperties(properties);
   else if(dynamic_cast<MP4::File* >(this))
     return dynamic_cast<MP4::File* >(this)->setProperties(properties);
+  else if(dynamic_cast<ASF::File* >(this))
+    return dynamic_cast<ASF::File* >(this)->setProperties(properties);
   else
     return tag()->setProperties(properties);
 }
index 51d5df6fe31892a5462b8d2249c71393a9633db8..2be49ddb0572f791820fb4db61541e3fdd831e04 100644 (file)
@@ -83,6 +83,7 @@ namespace TagLib {
    *  - MOOD
    *  - COMMENT 
    *  - MEDIA
+   *  - LABEL
    *  - CATALOGNUMBER
    *  - BARCODE
    *
index 0cd1f3d705d53e7672f71cf12a4eaf2ead4f1eff..8610c24bf4bd47a36e5e2a38d40a533ccf28216f 100644 (file)
@@ -3,6 +3,7 @@
 #include <tag.h>
 #include <tstringlist.h>
 #include <tbytevectorlist.h>
+#include <tpropertymap.h>
 #include <asffile.h>
 #include <cppunit/extensions/HelperMacros.h>
 #include "utils.h"
@@ -13,7 +14,7 @@ using namespace TagLib;
 class TestASF : public CppUnit::TestFixture
 {
   CPPUNIT_TEST_SUITE(TestASF);
-  CPPUNIT_TEST(testProperties);
+  CPPUNIT_TEST(testAudioProperties);
   CPPUNIT_TEST(testRead);
   CPPUNIT_TEST(testSaveMultipleValues);
   CPPUNIT_TEST(testSaveStream);
@@ -22,11 +23,12 @@ class TestASF : public CppUnit::TestFixture
   CPPUNIT_TEST(testSaveLargeValue);
   CPPUNIT_TEST(testSavePicture);
   CPPUNIT_TEST(testSaveMultiplePictures);
+  CPPUNIT_TEST(testProperties);
   CPPUNIT_TEST_SUITE_END();
 
 public:
 
-  void testProperties()
+  void testAudioProperties()
   {
     ASF::File f(TEST_FILE_PATH_C("silence-1.wma"));
     CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->length());
@@ -215,6 +217,39 @@ public:
     delete f;
   }
 
+  void testProperties()
+  {
+    ASF::File f(TEST_FILE_PATH_C("silence-1.wma"));
+    
+    PropertyMap tags = f.properties();
+
+    tags["TRACKNUMBER"] = StringList("2");
+    tags["DISCNUMBER"] = StringList("3");
+    tags["BPM"] = StringList("123");
+    tags["ARTIST"] = StringList("Foo Bar");
+    f.setProperties(tags);
+
+    tags = f.properties();
+
+    CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), f.tag()->artist());
+    CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]);
+
+    CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/BeatsPerMinute"));
+    CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/BeatsPerMinute"].size());
+    CPPUNIT_ASSERT_EQUAL(String("123"), f.tag()->attributeListMap()["WM/BeatsPerMinute"].front().toString());
+    CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]);
+
+    CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/TrackNumber"));
+    CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/TrackNumber"].size());
+    CPPUNIT_ASSERT_EQUAL(String("2"), f.tag()->attributeListMap()["WM/TrackNumber"].front().toString());
+    CPPUNIT_ASSERT_EQUAL(StringList("2"), tags["TRACKNUMBER"]);
+
+    CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/PartOfSet"));
+    CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/PartOfSet"].size());
+    CPPUNIT_ASSERT_EQUAL(String("3"), f.tag()->attributeListMap()["WM/PartOfSet"].front().toString());
+    CPPUNIT_ASSERT_EQUAL(StringList("3"), tags["DISCNUMBER"]);
+  }
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestASF);