mirror of
https://github.com/taglib/taglib.git
synced 2026-08-14 06:17:00 -04:00
fix(matroska): find Segments past the fast scan limit (#1398)
Element::factory() rejects any element whose declared size runs past the bound it is given, and read() passes the Fast scan limit as that bound. A Segment spans practically the whole file, so under ReadStyle::Fast every Matroska over 512 KiB is rejected and no tags are read: EBML: datasize too great: 1003369 > (524288 - 52) Failed to find Matroska segment The limit is readLimited()'s, which already applies it to skip Cues and to bound the walk over a segment with no usable SeekHead. The lookup only needs the file length. Correctly handle offsets and scan limits: - maxOffset: Maximum offset from the beginning of the file; the end of the element must be before this offset. - scanLimit: Offset from the current file position until which scanning for elements is allowed. Normally, elements are scanned up to the end of the enclosing master element or the end of the file, but in Fast reading mode, it is limited to FAST_SCAN_LIMIT, which is 512 kB. - maxScanOffset: scanLimit from the current file position --------- Co-authored-by: Claude Opus 5 <[email protected]> Co-authored-by: Urs Fleisch <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
Urs Fleisch
parent
819bfce872
commit
ce3b45f186
@@ -161,6 +161,7 @@ class TestMatroska : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testSaveTypesNoTrailingVoid);
|
||||
CPPUNIT_TEST(testSaveTypesReclaimVoid);
|
||||
CPPUNIT_TEST(testUnknownSizeSegment);
|
||||
CPPUNIT_TEST(testFastReadStyleLargeSegment);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -1778,6 +1779,43 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testFastReadStyleLargeSegment()
|
||||
{
|
||||
ScopedFileCopy copy("tags-before-cues", ".mkv");
|
||||
string newname = copy.fileName();
|
||||
|
||||
// Grow the segment past FAST_SCAN_LIMIT, as every real world file is.
|
||||
{
|
||||
PlainFile file(newname.c_str());
|
||||
ByteVector fileData = file.readAll();
|
||||
CPPUNIT_ASSERT_EQUAL(3412U, fileData.size());
|
||||
|
||||
// Void element, appended to the segment so the existing seek positions still hold.
|
||||
const unsigned int voidDataSize = 1024 * 1024;
|
||||
ByteVector voidElement("\xec", 1);
|
||||
voidElement.append(ByteVector::fromULongLong(0x0100000000000000ULL | voidDataSize));
|
||||
voidElement.append(ByteVector(voidDataSize, '\0'));
|
||||
|
||||
// Segment: 4 byte ID at 0x28, 8 byte size VINT at 0x2c, data from 0x34 to EOF.
|
||||
ByteVector newData = fileData.mid(0, 0x2c);
|
||||
newData.append(ByteVector::fromULongLong(
|
||||
0x0100000000000000ULL | (fileData.size() - 0x34 + voidElement.size())));
|
||||
newData.append(fileData.mid(0x34));
|
||||
newData.append(voidElement);
|
||||
|
||||
file.seek(0);
|
||||
file.writeBlock(newData);
|
||||
}
|
||||
|
||||
for(auto readStyle : {AudioProperties::Fast, AudioProperties::Average,
|
||||
AudioProperties::Accurate}) {
|
||||
Matroska::File f(newname.c_str(), true, readStyle);
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(f.tag(false));
|
||||
CPPUNIT_ASSERT_EQUAL(String("handbrake"), f.tag()->title());
|
||||
}
|
||||
}
|
||||
|
||||
void testUnknownSizeSegment()
|
||||
{
|
||||
ScopedFileCopy copy("no-tags", ".mka");
|
||||
|
||||
Reference in New Issue
Block a user