diff --git a/taglib/ape/apetag.cpp b/taglib/ape/apetag.cpp index 1f3f84a2..92d106c4 100644 --- a/taglib/ape/apetag.cpp +++ b/taglib/ape/apetag.cpp @@ -197,6 +197,7 @@ void APE::Tag::fromDict(const TagDict &orig_dict) { TagDict dict(orig_dict); // make a local copy that can be modified + // see comment in toDict() about TRACKNUMBER and YEAR if (dict.contains("TRACKNUMBER")) { dict.insert("TRACK", dict["TRACKNUMBER"]); dict.erase("TRACKNUMBER"); diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index 9c5e50f4..dd3e97a7 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -334,18 +334,22 @@ void ID3v2::Tag::removeFrames(const ByteVector &id) removeFrame(*it, true); } -TagDict ID3v2::Tag::toDict() const +TagDict ID3v2::Tag::toDict(StringList *ignoreInfo) const { TagDict dict; FrameList::ConstIterator frameIt = frameList().begin(); for (; frameIt != frameList().end(); ++frameIt) { ByteVector id = (*frameIt)->frameID(); - if (ignored(id)) + if (ignored(id)) { debug("toDict() found ignored id3 frame: " + id); - else if (deprecated(id)) + if (ignoreInfo) + ignoreInfo->append(String(id) + " frame is not supported"); + } else if (deprecated(id)) { debug("toDict() found deprecated id3 frame: " + id); - else { + if (ignoreInfo) + ignoreInfo->append(String(id) + " frame is deprecated"); + } else { // in the future, something like dict[frame->tagName()].append(frame->values()) // might replace the following lines. KeyValuePair kvp = parseFrame(*frameIt); diff --git a/taglib/mpeg/id3v2/id3v2tag.h b/taglib/mpeg/id3v2/id3v2tag.h index 3f731282..33d9a33c 100644 --- a/taglib/mpeg/id3v2/id3v2tag.h +++ b/taglib/mpeg/id3v2/id3v2tag.h @@ -264,8 +264,13 @@ namespace TagLib { * Implements the unified tag dictionary interface -- export function. * This function does some work to translate the hard-specified ID3v2 * frame types into a free-form string-to-stringlist dictionary. + * + * If the optional pointer to a StringList is given, that list will + * be filled with a descriptive text for each ID3v2 frame that could + * not be incorporated into the dict interface (binary data, unsupported + * frames, ...). */ - TagDict toDict() const; + TagDict toDict(StringList *ignoredInfo = 0) const; /*! * Implements the unified tag dictionary interface -- import function. diff --git a/tests/test_apetag.cpp b/tests/test_apetag.cpp index 901a2aaf..fc38907f 100644 --- a/tests/test_apetag.cpp +++ b/tests/test_apetag.cpp @@ -15,6 +15,7 @@ class TestAPETag : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(TestAPETag); CPPUNIT_TEST(testIsEmpty); CPPUNIT_TEST(testIsEmpty2); + CPPUNIT_TEST(testDict); CPPUNIT_TEST_SUITE_END(); public: @@ -35,6 +36,21 @@ public: CPPUNIT_ASSERT(!tag.isEmpty()); } + void testDict() + { + APE::Tag tag; + TagDict dict = tag.toDict(); + CPPUNIT_ASSERT(dict.isEmpty()); + dict["ARTIST"] = String("artist 1"); + dict["ARTIST"].append("artist 2"); + dict["TRACKNUMBER"].append("17"); + tag.fromDict(dict); + CPPUNIT_ASSERT_EQUAL(String("17"), tag.itemListMap()["TRACK"].values()[0]); + CPPUNIT_ASSERT_EQUAL(2u, tag.itemListMap()["ARTIST"].values().size()); + CPPUNIT_ASSERT_EQUAL(String("artist 1"), tag.artist()); + CPPUNIT_ASSERT_EQUAL(17u, tag.track()); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestAPETag); diff --git a/tests/test_flac.cpp b/tests/test_flac.cpp index 90baa844..f9a0afa4 100644 --- a/tests/test_flac.cpp +++ b/tests/test_flac.cpp @@ -22,6 +22,7 @@ class TestFLAC : public CppUnit::TestFixture CPPUNIT_TEST(testRemoveAllPictures); CPPUNIT_TEST(testRepeatedSave); CPPUNIT_TEST(testSaveMultipleValues); + CPPUNIT_TEST(testDict); CPPUNIT_TEST_SUITE_END(); public: @@ -208,6 +209,27 @@ public: CPPUNIT_ASSERT_EQUAL(String("artist 2"), m["ARTIST"][1]); } + void testDict() + { + // test unicode & multiple values with dict interface + ScopedFileCopy copy("silence-44-s", ".flac"); + string newname = copy.fileName(); + + FLAC::File *f = new FLAC::File(newname.c_str()); + TagDict dict; + dict["ARTIST"].append("artøst 1"); + dict["ARTIST"].append("artöst 2"); + f->fromDict(dict); + f->save(); + delete f; + + f = new FLAC::File(newname.c_str()); + dict = f->toDict(); + CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["ARTIST"].size()); + CPPUNIT_ASSERT_EQUAL(String("artøst 1"), dict["ARTIST"][0]); + CPPUNIT_ASSERT_EQUAL(String("artöst 2"), dict["ARTIST"][1]); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC); diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 067bcd22..1823a5c3 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -553,20 +553,22 @@ public: ScopedFileCopy copy("rare_frames", ".mp3"); string newname = copy.fileName(); MPEG::File f(newname.c_str()); - TagDict dict = f.ID3v2Tag(false)->toDict(); + StringList ignored; + TagDict dict = f.ID3v2Tag(false)->toDict(&ignored); CPPUNIT_ASSERT_EQUAL(uint(6), dict.size()); CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION1"][0]); CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION1"][1]); CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION2"][0]); CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION2"][1]); - CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"][0]); CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"][0]); CPPUNIT_ASSERT_EQUAL(String("http://a.user.url"), dict["USERURL"][0]); CPPUNIT_ASSERT_EQUAL(String("http://a.user.url/with/empty/description"), dict["URL"][0]); CPPUNIT_ASSERT_EQUAL(String("A COMMENT"), dict["COMMENT"][0]); + CPPUNIT_ASSERT_EQUAL(String("UFID frame is not supported"), ignored[0]); + CPPUNIT_ASSERT_EQUAL(1u, ignored.size()); } };