]> granicus.if.org Git - taglib/commitdiff
Decode unsynchronized ID3v2 frames efficiently.
authorTsuda Kageyu <tsuda.kageyu@gmail.com>
Wed, 17 Feb 2016 18:07:38 +0000 (03:07 +0900)
committerTsuda Kageyu <tsuda.kageyu@gmail.com>
Wed, 17 Feb 2016 18:07:38 +0000 (03:07 +0900)
It makes a great difference when decoding huge unsynchronized ID3v2 frames.

NEWS
taglib/mpeg/id3v2/id3v2synchdata.cpp
tests/test_synchdata.cpp

diff --git a/NEWS b/NEWS
index 74695376869d09339da4d57d74efe7bc8395749e..5fbfb7ee7f6299be6906848b0b7fec0cfd2f416d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ TagLib 1.11 (Jan 30, 2016)
 
  * Better handling of PCM WAV files with a 'fact' chunk.
  * Better handling of corrupted APE tags.
+ * Efficient decoding of unsynchronized ID3v2 frames.
  * Fixed text encoding when saving certain frames in ID3v2.3 tags.
  * Several smaller bug fixes and performance improvements.
 
index b16c1987d658d72e2c81a433eb54c2328f465835..5ef419ece0fa6946bded2cfa8f4de8a2fb0bdf30 100644 (file)
@@ -74,11 +74,29 @@ ByteVector SynchData::fromUInt(unsigned int value)
 
 ByteVector SynchData::decode(const ByteVector &data)
 {
+  // We have this optimized method instead of using ByteVector::replace(),
+  // since it makes a great difference when decoding huge unsynchronized frames.
+
+  if(data.size() < 2)
+    return data;
+
   ByteVector result = data;
 
-  ByteVector pattern(2, char(0));
-  pattern[0] = '\xFF';
-  pattern[1] = '\x00';
+  char *begin = result.data();
+  char *end = begin + result.size();
+
+  char *dst = begin;
+  const char *src = begin;
+
+  do {
+    *dst++ = *src++;
+
+    if(*(src - 1) == '\xff' && *src == '\x00')
+      src++;
+
+  } while (src < end);
+
+  result.resize(static_cast<unsigned int>(dst - begin));
 
-  return result.replace(pattern, '\xFF');
+  return result;
 }
index 4cffee148cad40847b1026c6f9bbea0438741401..bbd74d8b0e9e9db17c488ebe9137ec5da21f866a 100644 (file)
@@ -40,6 +40,7 @@ class TestID3v2SynchData : public CppUnit::TestFixture
   CPPUNIT_TEST(testToUIntBrokenAndTooLarge);
   CPPUNIT_TEST(testDecode1);
   CPPUNIT_TEST(testDecode2);
+  CPPUNIT_TEST(testDecode3);
   CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -104,6 +105,14 @@ public:
     CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x44", 2), a);
   }
 
+  void testDecode3()
+  {
+    ByteVector a("\xff\xff\x00", 3);
+    a = ID3v2::SynchData::decode(a);
+    CPPUNIT_ASSERT_EQUAL((unsigned int)2, a.size());
+    CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\xff", 2), a);
+  }
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2SynchData);