diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index b821a440..a1e8b5ea 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -528,7 +528,11 @@ MP4::Tag::save() debug("MP4: Unknown item name \"" + name + "\""); } } - data = renderAtom("ilst", data); + // Leave data empty if there are no items. This will ensure that no meta atom + // is saved. + if (!data.isEmpty()) { + data = renderAtom("ilst", data); + } AtomList path = d->atoms->path("moov", "udta", "meta", "ilst"); if(path.size() == 4) { @@ -643,6 +647,9 @@ MP4::Tag::updateOffsets(long delta, long offset) void MP4::Tag::saveNew(ByteVector data) { + if(data.isEmpty()) + return; + data = renderAtom("meta", ByteVector(4, '\0') + renderAtom("hdlr", ByteVector(8, '\0') + ByteVector("mdirappl") + ByteVector(9, '\0')) + @@ -699,20 +706,40 @@ MP4::Tag::saveExisting(ByteVector data, const AtomList &path) } long delta = data.size() - length; - if(delta > 0 || (delta < 0 && delta > -8)) { - data.append(padIlst(data)); - delta = data.size() - length; - } - else if(delta < 0) { - data.append(padIlst(data, -delta - 8)); - delta = 0; - } + if(!data.isEmpty()) { + if(delta > 0 || (delta < 0 && delta > -8)) { + data.append(padIlst(data)); + delta = data.size() - length; + } + else if(delta < 0) { + data.append(padIlst(data, -delta - 8)); + delta = 0; + } - d->file->insert(data, offset, length); + d->file->insert(data, offset, length); - if(delta) { - updateParents(path, delta, 1); - updateOffsets(delta, offset); + if(delta) { + updateParents(path, delta, 1); + updateOffsets(delta, offset); + } + } + else { + // Strip meta + MP4::Atom *udta = *(--it); + AtomList &udtaChildren = udta->children; + AtomList::Iterator metaIt = udtaChildren.find(meta); + if (metaIt != udtaChildren.end()) { + offset = meta->offset; + delta = - meta->length; + udtaChildren.erase(metaIt); + d->file->removeBlock(meta->offset, meta->length); + delete meta; + + if(delta) { + updateParents(path, delta, 2); + updateOffsets(delta, offset); + } + } } } diff --git a/tests/test_mp4.cpp b/tests/test_mp4.cpp index 5f96c9c0..6e44421a 100644 --- a/tests/test_mp4.cpp +++ b/tests/test_mp4.cpp @@ -65,6 +65,7 @@ class TestMP4 : public CppUnit::TestFixture CPPUNIT_TEST(testRepeatedSave); CPPUNIT_TEST(testWithZeroLengthAtom); CPPUNIT_TEST(testEmptyValuesRemoveItems); + CPPUNIT_TEST(testRemoveMetadata); CPPUNIT_TEST_SUITE_END(); public: @@ -654,6 +655,39 @@ public: CPPUNIT_ASSERT_EQUAL(zeroUInt, tag->track()); CPPUNIT_ASSERT(!tag->contains("trkn")); } + + void testRemoveMetadata() + { + ScopedFileCopy copy("no-tags", ".m4a"); + + { + MP4::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasMP4Tag()); + MP4::Tag *tag = f.tag(); + CPPUNIT_ASSERT(tag->isEmpty()); + tag->setTitle("TITLE"); + f.save(); + } + { + MP4::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(f.hasMP4Tag()); + MP4::Tag *tag = f.tag(); + CPPUNIT_ASSERT(!tag->isEmpty()); + tag->setTitle(""); + f.save(); + } + { + MP4::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.isValid()); + CPPUNIT_ASSERT(!f.hasMP4Tag()); + CPPUNIT_ASSERT(f.tag()->isEmpty()); + CPPUNIT_ASSERT(fileEqual( + copy.fileName(), + TEST_FILE_PATH_C("no-tags.m4a"))); + } + } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);