mirror of
https://github.com/taglib/taglib.git
synced 2026-11-05 22:18:50 -05:00
ID3v2: Render at most 255 child elements in a CTOC frame (#1479)
The entry count is a single byte, so a table of more than 255 children wrapped the count while still writing every child element ID, and readers took the surplus IDs as embedded frames. Render the first 255 with a matching count, as renderChplData does for Nero chapters.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "tableofcontentsframe.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "tpropertymap.h"
|
||||
@@ -293,8 +294,13 @@ ByteVector TableOfContentsFrame::renderFields() const
|
||||
if(d->isOrdered)
|
||||
flags += 1;
|
||||
data.append(flags);
|
||||
data.append(static_cast<char>(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<char>(count));
|
||||
unsigned int i = 0;
|
||||
for(const auto &element : std::as_const(d->childElements)) {
|
||||
if(i++ >= count)
|
||||
break;
|
||||
data.append(element);
|
||||
data.append('\0');
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user