mirror of
https://github.com/taglib/taglib.git
synced 2025-05-27 21:20:26 -04:00
Correctly parse MP4 non-full meta atoms (#1041)
There are m4a files with regular (non-full) meta atoms. When such a meta atom is not correctly parsed, the subsequent atoms are not recognized and offsets will not be adjusted when atoms are added, which will corrupt the MP4 file. This change will look behind the meta atom to check if the next atom follows directly, i.e. without the four bytes with version and flags as they exist in full atoms. In such a case, these four bytes will not be skipped. Witnesses of this strange format specification are https://leo-van-stee.github.io/ https://github.com/axiomatic-systems/Bento4/blob/v1.6.0-639/Source/C%2B%2B/Core/Ap4ContainerAtom.cpp#L60
This commit is contained in:
parent
e255e749e8
commit
197d2a684b
@ -85,7 +85,25 @@ MP4::Atom::Atom(File *file)
|
||||
for(int i = 0; i < numContainers; i++) {
|
||||
if(name == containers[i]) {
|
||||
if(name == "meta") {
|
||||
file->seek(4, File::Current);
|
||||
long posAfterMeta = file->tell();
|
||||
ByteVector nextSize = file->readBlock(8).mid(4, 4);
|
||||
static const char *const metaChildrenNames[] = {
|
||||
"hdlr", "ilst", "mhdr", "ctry", "lang"
|
||||
};
|
||||
bool metaIsFullAtom = true;
|
||||
for(size_t j = 0;
|
||||
j < sizeof(metaChildrenNames) / sizeof(metaChildrenNames[0]);
|
||||
++j) {
|
||||
if(nextSize == metaChildrenNames[j]) {
|
||||
// meta is not a full atom (i.e. not followed by version, flags). It
|
||||
// is followed by the size and type of the first child atom.
|
||||
metaIsFullAtom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Only skip next four bytes, which contain version and flags, if meta
|
||||
// is a full atom.
|
||||
file->seek(posAfterMeta + (metaIsFullAtom ? 4 : 0));
|
||||
}
|
||||
else if(name == "stsd") {
|
||||
file->seek(8, File::Current);
|
||||
|
BIN
tests/data/non-full-meta.m4a
Normal file
BIN
tests/data/non-full-meta.m4a
Normal file
Binary file not shown.
@ -66,6 +66,7 @@ class TestMP4 : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testWithZeroLengthAtom);
|
||||
CPPUNIT_TEST(testEmptyValuesRemoveItems);
|
||||
CPPUNIT_TEST(testRemoveMetadata);
|
||||
CPPUNIT_TEST(testNonFullMetaAtom);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@ -686,6 +687,27 @@ public:
|
||||
TEST_FILE_PATH_C("no-tags.m4a")));
|
||||
}
|
||||
}
|
||||
|
||||
void testNonFullMetaAtom()
|
||||
{
|
||||
{
|
||||
MP4::File f(TEST_FILE_PATH_C("non-full-meta.m4a"));
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(f.hasMP4Tag());
|
||||
|
||||
CPPUNIT_ASSERT(f.tag()->contains("covr"));
|
||||
MP4::CoverArtList l = f.tag()->item("covr").toCoverArtList();
|
||||
CPPUNIT_ASSERT_EQUAL((unsigned int)2, l.size());
|
||||
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
|
||||
CPPUNIT_ASSERT_EQUAL((unsigned int)79, l[0].data().size());
|
||||
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format());
|
||||
CPPUNIT_ASSERT_EQUAL((unsigned int)287, l[1].data().size());
|
||||
|
||||
PropertyMap properties = f.properties();
|
||||
CPPUNIT_ASSERT_EQUAL(StringList("Test Artist!!!!"), properties["ARTIST"]);
|
||||
CPPUNIT_ASSERT_EQUAL(StringList("FAAC 1.24"), properties["ENCODEDBY"]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);
|
||||
|
Loading…
Reference in New Issue
Block a user