diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index c6aa4f93..267a45d0 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -81,6 +81,11 @@ public: static const Latin1StringHandler defaultStringHandler; const ID3v2::Latin1StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler; +namespace +{ + const uint DefaultPaddingSize = 1024; +} + //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// @@ -596,15 +601,21 @@ ByteVector ID3v2::Tag::render(int version) const // Compute the amount of padding, and append that to tagData. - uint paddingSize = 0; - uint originalSize = d->header.tagSize(); + uint paddingSize = DefaultPaddingSize; - if(tagData.size() < originalSize) - paddingSize = originalSize - tagData.size(); - else - paddingSize = 1024; + if(d->file && tagData.size() < d->header.tagSize()) { + paddingSize = d->header.tagSize() - tagData.size(); - tagData.append(ByteVector(paddingSize, char(0))); + // Padding won't increase beyond 1% of the file size. + + if(paddingSize > DefaultPaddingSize) { + const uint threshold = d->file->length() / 100; // should be ulonglong in taglib2. + if(paddingSize > threshold) + paddingSize = DefaultPaddingSize; + } + } + + tagData.append(ByteVector(paddingSize, '\0')); // Set the version and data size. d->header.setMajorVersion(version); diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 054ae07d..e0d2d176 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -91,6 +91,7 @@ class TestID3v2 : public CppUnit::TestFixture CPPUNIT_TEST(testRenderChapterFrame); CPPUNIT_TEST(testParseTableOfContentsFrame); CPPUNIT_TEST(testRenderTableOfContentsFrame); + CPPUNIT_TEST(testShrinkPadding); CPPUNIT_TEST_SUITE_END(); public: @@ -1005,6 +1006,39 @@ public: f.render()); } + void testShrinkPadding() + { + ScopedFileCopy copy("xing", ".mp3"); + string newname = copy.fileName(); + + { + MPEG::File f(newname.c_str()); + ID3v2::Tag *tag = f.ID3v2Tag(true); + + ID3v2::TextIdentificationFrame *frame1 = new ID3v2::TextIdentificationFrame("TIT2"); + frame1->setText("Title"); + tag->addFrame(frame1); + + ID3v2::AttachedPictureFrame *frame2 = new ID3v2::AttachedPictureFrame(); + frame2->setPicture(ByteVector(100 * 1024, '\xff')); + tag->addFrame(frame2); + + f.save(); + CPPUNIT_ASSERT(f.length() > 100 * 1024); + } + + { + MPEG::File f(newname.c_str()); + CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); + + ID3v2::Tag *tag = f.ID3v2Tag(); + tag->removeFrames("APIC"); + + f.save(); + CPPUNIT_ASSERT(f.length() < 10 * 1024); + } + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2);