Decode unsynchronized ID3v2 frames efficiently.

It makes a great difference when decoding huge unsynchronized ID3v2 frames.
This commit is contained in:
Tsuda Kageyu 2016-02-18 03:07:38 +09:00
parent dadfe79799
commit a9acca5d81
3 changed files with 32 additions and 4 deletions

1
NEWS
View File

@ -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.

View 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();
return result.replace(pattern, '\xFF');
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;
}

View 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);