FileRef: Rewind the stream before detecting the type by content (#1487)

A parser tried for the file extension may leave the stream anywhere, and Matroska::File::read() starts at the current position, so a Matroska file under an extension whose parser rejects it gave a null FileRef.
This commit is contained in:
Ryan Francesconi
2026-11-01 07:40:57 +01:00
committed by GitHub
parent 8875f397d9
commit 52d0f7cc5e
2 changed files with 35 additions and 0 deletions
+4
View File
@@ -579,7 +579,9 @@ void FileRef::parse(FileName fileName, bool readAudioProperties,
return;
// At last, try to resolve file types based on the actual content.
// A parser tried for the extension may have left the stream anywhere.
d->stream->seek(0);
d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
@@ -612,7 +614,9 @@ void FileRef::parse(IOStream *stream, bool readAudioProperties,
return;
// At last, try to resolve file types based on the actual content of the file.
// A parser tried for the extension may have left the stream anywhere.
stream->seek(0);
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
}
+31
View File
@@ -60,6 +60,9 @@
#ifdef TAGLIB_WITH_MOD
#include "xmfile.h"
#endif
#ifdef TAGLIB_WITH_MATROSKA
#include "matroskafile.h"
#endif
#ifdef TAGLIB_WITH_DSF
#include "dsffile.h"
#include "dsdifffile.h"
@@ -141,6 +144,9 @@ class TestFileRef : public CppUnit::TestFixture
#ifdef TAGLIB_WITH_DSF
CPPUNIT_TEST(testDSF);
CPPUNIT_TEST(testDSDIFF);
#endif
#ifdef TAGLIB_WITH_MATROSKA
CPPUNIT_TEST(testMatroskaWithOtherExtension);
#endif
CPPUNIT_TEST_SUITE_END();
@@ -403,6 +409,31 @@ public:
}
#endif
#ifdef TAGLIB_WITH_MATROSKA
void testMatroskaWithOtherExtension()
{
// The parsers for these extensions reject Matroska, so the file is found
// by content detection after a failed parse.
for(const char *ext : { ".flac", ".m4a" }) {
ScopedFileCopy copy("no-tags", ".mka");
const string newname = copy.fileName() + ext;
CPPUNIT_ASSERT_EQUAL(0, std::rename(copy.fileName().c_str(), newname.c_str()));
{
FileRef f(newname.c_str());
CPPUNIT_ASSERT(dynamic_cast<Matroska::File *>(f.file()));
CPPUNIT_ASSERT(!f.isNull());
}
{
FileStream s(newname.c_str());
FileRef f(&s);
CPPUNIT_ASSERT(dynamic_cast<Matroska::File *>(f.file()));
CPPUNIT_ASSERT(!f.isNull());
}
deleteFile(newname);
}
}
#endif
void testUnsupported()
{
FileRef f1(TEST_FILE_PATH_C("no-extension"));