]> granicus.if.org Git - taglib/commitdiff
Simple ID3v2.4 => ID3v2.3 frame migration
authorLukáš Lalinský <lalinsky@gmail.com>
Wed, 16 Mar 2011 16:14:36 +0000 (17:14 +0100)
committerLukáš Lalinský <lalinsky@gmail.com>
Wed, 16 Mar 2011 16:14:36 +0000 (17:14 +0100)
taglib/mpeg/id3v2/id3v2tag.cpp
taglib/mpeg/id3v2/id3v2tag.h
tests/test_id3v2.cpp

index c85ef59d0355e4d1226f98fbe4a80a90e4033e2b..6908c1b01373f1005d6ee0c32dc234759f0e7a81 100644 (file)
@@ -334,6 +334,61 @@ ByteVector ID3v2::Tag::render() const
   return render(4);
 }
 
+void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
+{
+  const char *unsupportedFrames[] = {
+    "ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG",
+    "TMOO", "TPRO", "TSOA", "TSOT", "TSST", "TSOP", "TIPL",
+    "TMCL", 0
+  };
+  ID3v2::TextIdentificationFrame *frameTDOR = 0;
+  ID3v2::TextIdentificationFrame *frameTDRC = 0;
+  for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++) {
+    ID3v2::Frame *frame = *it;
+    ByteVector frameID = frame->header()->frameID();
+    for(int i = 0; unsupportedFrames[i]; i++) {
+      if(frameID == unsupportedFrames[i]) {
+        debug("A frame that is not supported in ID3v2.3 \'"
+          + String(frameID) + "\' has been discarded");
+        frame = 0;
+        break;
+      }
+    }
+    if(frame && frameID == "TDOR") {
+      frameTDOR = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
+      frame = 0;
+    }
+    if(frame && frameID == "TDRC") {
+      frameTDRC = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
+      frame = 0;
+    }
+    if(frame) {
+      frames->append(frame);
+    }
+  }
+  if(frameTDOR) {
+    String content = frameTDOR->toString();
+    if(content.size() >= 4) {
+      ID3v2::TextIdentificationFrame *frameTORY = new ID3v2::TextIdentificationFrame("TORY", String::Latin1);
+      frameTORY->setText(content.substr(0, 4));
+      frames->append(frameTORY);
+      newFrames->append(frameTORY);
+    }
+  }
+  if(frameTDRC) {
+    // FIXME we can do better here, define also TDAT and TIME
+    String content = frameTDRC->toString();
+    if(content.size() >= 4) {
+      ID3v2::TextIdentificationFrame *frameTYER = new ID3v2::TextIdentificationFrame("TYER", String::Latin1);
+      frameTYER->setText(content.substr(0, 4));
+      frames->append(frameTYER);
+      newFrames->append(frameTYER);
+    }
+  }
+  // FIXME migrate TIPL and TMCL to IPLS
+}
+
+
 ByteVector ID3v2::Tag::render(int version) const
 {
   // We need to render the "tag data" first so that we have to correct size to
@@ -347,7 +402,18 @@ ByteVector ID3v2::Tag::render(int version) const
 
   // Loop through the frames rendering them and adding them to the tagData.
 
-  for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++) {
+  FrameList newFrames;
+  newFrames.setAutoDelete(true);
+
+  FrameList frameList;
+  if(version == 4) {
+    frameList = d->frameList;
+  }
+  else {
+    downgradeFrames(&frameList, &newFrames);
+  }
+
+  for(FrameList::Iterator it = frameList.begin(); it != frameList.end(); it++) {
     (*it)->header()->setVersion(version);
     if((*it)->header()->frameID().size() != 4) {
       debug("A frame of unsupported or unknown type \'"
index 137139bd56a33f1612bf9166dec32ae4ef14d4ac..4a52854afb0cb148a90d8ff2bb0125a06ba6357d 100644 (file)
@@ -295,6 +295,8 @@ namespace TagLib {
        */
       void setTextFrame(const ByteVector &id, const String &value);
 
+      void downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const;
+
     private:
       Tag(const Tag &);
       Tag &operator=(const Tag &);
index 3460168c6356608be2ecfc2f9e1703bd16a9fd4c..84074585e85a8553c409d868ec63d6db451fff41 100644 (file)
@@ -64,6 +64,7 @@ class TestID3v2 : public CppUnit::TestFixture
   CPPUNIT_TEST(testUpdateGenre23_2);
   CPPUNIT_TEST(testUpdateGenre24);
   CPPUNIT_TEST(testUpdateDate22);
+  CPPUNIT_TEST(testDowngradeTo23);
   // CPPUNIT_TEST(testUpdateFullDate22); TODO TYE+TDA should be upgraded to TDRC together
   CPPUNIT_TEST(testCompressedFrameWithBrokenLength);
   CPPUNIT_TEST_SUITE_END();
@@ -474,6 +475,48 @@ public:
     CPPUNIT_ASSERT_EQUAL(String("2010-04-03"), f.ID3v2Tag()->frameListMap()["TDRC"].front()->toString());
   }
 
+  void testDowngradeTo23()
+  {
+    ScopedFileCopy copy("xing", ".mp3");
+    string newname = copy.fileName();
+
+    ID3v2::TextIdentificationFrame *tf;
+    MPEG::File foo(newname.c_str());
+    tf = new ID3v2::TextIdentificationFrame("TDOR", String::Latin1);
+    tf->setText("2011-03-16");
+    foo.ID3v2Tag()->addFrame(tf);
+    tf = new ID3v2::TextIdentificationFrame("TDRC", String::Latin1);
+    tf->setText("2012-04-17");
+    foo.ID3v2Tag()->addFrame(tf);
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDRL", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDTG", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TMOO", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TPRO", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOA", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOT", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSST", String::Latin1));
+    foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOP", String::Latin1));
+    foo.save(MPEG::File::AllTags, true, 3);
+
+    MPEG::File bar(newname.c_str());
+    tf = static_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TDOR").front());
+    CPPUNIT_ASSERT(tf);
+    CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), tf->fieldList().size());
+    CPPUNIT_ASSERT_EQUAL(String("2011"), tf->fieldList().front());
+    tf = static_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TDRC").front());
+    CPPUNIT_ASSERT(tf);
+    CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), tf->fieldList().size());
+    CPPUNIT_ASSERT_EQUAL(String("2012"), tf->fieldList().front());
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDRL"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDTG"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TMOO"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TPRO"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOA"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOT"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSST"));
+    CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOP"));
+  }
+
   void testCompressedFrameWithBrokenLength()
   {
     MPEG::File f("data/compressed_id3_frame.mp3", false);