From 834d9d6b230dec1a0441ea391c4f872079b663ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Fri, 24 Jul 2009 13:08:51 +0000 Subject: [PATCH] Partial support for 64-bit atoms We still can't handle actual 64-bit atoms, but we can handle 32-bit sizes stored in 64 bits. CCBUG:198730 git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1001897 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- taglib/mp4/mp4atom.cpp | 15 +++++++++++---- taglib/mp4/mp4tag.cpp | 17 ++++++++++++++--- tests/data/64bit.mp4 | Bin 0 -> 85 bytes tests/test_mp4.cpp | 27 +++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 tests/data/64bit.mp4 diff --git a/taglib/mp4/mp4atom.cpp b/taglib/mp4/mp4atom.cpp index e1a36828..ba07409a 100644 --- a/taglib/mp4/mp4atom.cpp +++ b/taglib/mp4/mp4atom.cpp @@ -47,10 +47,17 @@ MP4::Atom::Atom(File *file) length = header.mid(0, 4).toUInt(); if (length == 1) { - debug("MP4: 64-bit atoms are not supported"); - length = 0; - file->seek(0, File::End); - return; + long long longLength = file->readBlock(8).toLongLong(); + if (longLength >= 8 && longLength <= 0xFFFFFFFF) { + // The atom has a 64-bit length, but it's actually a 32-bit value + length = (long)longLength; + } + else { + debug("MP4: 64-bit atoms are not supported"); + length = 0; + file->seek(0, File::End); + return; + } } if (length < 8) { debug("MP4: Invalid atom size"); diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index 645d4976..3196f101 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -314,9 +314,20 @@ MP4::Tag::updateParents(AtomList &path, long delta, int ignore) { for(unsigned int i = 0; i < path.size() - ignore; i++) { d->file->seek(path[i]->offset); - long size = d->file->readBlock(4).toUInt() + delta; - d->file->seek(path[i]->offset); - d->file->writeBlock(ByteVector::fromUInt(size)); + long size = d->file->readBlock(4).toUInt(); + // 64-bit + if (size == 1) { + d->file->seek(4, File::Current); // Skip name + long long longSize = d->file->readBlock(8).toLongLong(); + // Seek the offset of the 64-bit size + d->file->seek(path[i]->offset + 8); + d->file->writeBlock(ByteVector::fromLongLong(longSize + delta)); + } + // 32-bit + else { + d->file->seek(path[i]->offset); + d->file->writeBlock(ByteVector::fromUInt(size + delta)); + } } } diff --git a/tests/data/64bit.mp4 b/tests/data/64bit.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..0bd7f9f33dfa28317996eab962cce5cb2d2afc0b GIT binary patch literal 85 zcmZQzU|`J6&o5(u0AC=*SejCj2<6*?__?WYzAjW;F*B#Q1jv?5F38LQ(t;_8U^Sv3 Gc}4)(BMUG9 literal 0 HcmV?d00001 diff --git a/tests/test_mp4.cpp b/tests/test_mp4.cpp index 04ad729a..9732a5bb 100644 --- a/tests/test_mp4.cpp +++ b/tests/test_mp4.cpp @@ -18,6 +18,7 @@ class TestMP4 : public CppUnit::TestFixture CPPUNIT_TEST(testFreeForm); CPPUNIT_TEST(testUpdateStco); CPPUNIT_TEST(testSaveExisingWhenIlstIsLast); + CPPUNIT_TEST(test64BitAtom); CPPUNIT_TEST_SUITE_END(); public: @@ -118,6 +119,32 @@ public: deleteFile(filename); } + void test64BitAtom() + { + string filename = copyFile("64bit", ".mp4"); + + MP4::File *f = new MP4::File(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool()); + + MP4::Atoms *atoms = new MP4::Atoms(f); + MP4::Atom *moov = atoms->atoms[0]; + CPPUNIT_ASSERT_EQUAL(long(77), moov->length); + + f->tag()->itemListMap()["pgap"] = 1; + f->save(); + + f = new MP4::File(filename.c_str()); + CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool()); + CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["pgap"].toBool()); + + atoms = new MP4::Atoms(f); + moov = atoms->atoms[0]; + // original size + 'pgap' size + padding + CPPUNIT_ASSERT_EQUAL(long(77 + 25 + 974), moov->length); + + deleteFile(filename); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);