diff --git a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp index cac8f7f3..d4767393 100644 --- a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp +++ b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp @@ -25,6 +25,7 @@ #include "tableofcontentsframe.h" +#include #include #include "tpropertymap.h" @@ -293,8 +294,13 @@ ByteVector TableOfContentsFrame::renderFields() const if(d->isOrdered) flags += 1; data.append(flags); - data.append(static_cast(entryCount())); + // The entry count is a single byte, so only the first 255 child elements are rendered. + const unsigned int count = std::min(entryCount(), 255U); + data.append(static_cast(count)); + unsigned int i = 0; for(const auto &element : std::as_const(d->childElements)) { + if(i++ >= count) + break; data.append(element); data.append('\0'); } diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 502a755e..ba2127a4 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -137,6 +137,7 @@ class TestID3v2 : public CppUnit::TestFixture CPPUNIT_TEST(testRenderChapterFrame); CPPUNIT_TEST(testParseTableOfContentsFrame); CPPUNIT_TEST(testRenderTableOfContentsFrame); + CPPUNIT_TEST(testRenderTableOfContentsFrameWithManyChildren); CPPUNIT_TEST(testShrinkPadding); CPPUNIT_TEST(testEmptyFrame); CPPUNIT_TEST(testDuplicateTags); @@ -1707,6 +1708,28 @@ public: f.render()); } + void testRenderTableOfContentsFrameWithManyChildren() + { + const unsigned int counts[] = { 255, 256, 300 }; + for(unsigned int count : counts) { + ID3v2::Header header; + ID3v2::TableOfContentsFrame f(&header, "CTOC"); + f.setElementID("T"); + for(unsigned int i = 0; i < count; ++i) + f.addChildElement(ByteVector("C") + ByteVector(String::number(i).toCString())); + auto eF = new ID3v2::TextIdentificationFrame("TIT2"); + eF->setText("TC1"); + f.addEmbeddedFrame(eF); + + ID3v2::TableOfContentsFrame parsed(&header, f.render()); + CPPUNIT_ASSERT_EQUAL(255U, parsed.entryCount()); + CPPUNIT_ASSERT_EQUAL(ByteVector("C254"), parsed.childElements().back()); + CPPUNIT_ASSERT_EQUAL(1U, parsed.embeddedFrameList().size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("TIT2"), + parsed.embeddedFrameList().front()->frameID()); + } + } + void testShrinkPadding() { ScopedFileCopy copy("xing", ".mp3");