]> granicus.if.org Git - taglib/commitdiff
Partial support for 64-bit atoms
authorLukáš Lalinský <lalinsky@gmail.com>
Fri, 24 Jul 2009 13:08:51 +0000 (13:08 +0000)
committerLukáš Lalinský <lalinsky@gmail.com>
Fri, 24 Jul 2009 13:08:51 +0000 (13:08 +0000)
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
taglib/mp4/mp4tag.cpp
tests/data/64bit.mp4 [new file with mode: 0644]
tests/test_mp4.cpp

index e1a36828e21c036b2c316279fb6dce14079f6e93..ba07409a39593f20e264bd1a3a91a46c4b36c14f 100644 (file)
@@ -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");
index 645d4976545c8be2ea9bf05d6e9d3cc8eaddce6e..3196f101ea8bd3976e6c12cc2deaee70c18cc007 100644 (file)
@@ -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 (file)
index 0000000..0bd7f9f
Binary files /dev/null and b/tests/data/64bit.mp4 differ
index 04ad729aff600296b5b28c4b82263c6bf11d01e8..9732a5bb716d66b78bdb8b40677cda40da7374a4 100644 (file)
@@ -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);