mirror of
https://github.com/taglib/taglib.git
synced 2026-11-06 22:48:48 -05:00
ID3v2: Skip an unreadable frame instead of ending the tag (#1483)
A frame that cannot be read, such as one with an invalid ID, is now skipped when another frame, padding or the end of the frames follows where its size ends; anything else still ends the tag as before. Previously every frame after it was dropped, and a save then deleted them from the file.
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "tpropertymap.h"
|
||||
#include "tfilestream.h"
|
||||
#include "id3v2synchdata.h"
|
||||
#include "tzlib.h"
|
||||
#include "id3v2tag.h"
|
||||
#include "mpegfile.h"
|
||||
@@ -141,6 +143,7 @@ class TestID3v2 : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testRenderTableOfContentsFrameWithManyChildren);
|
||||
CPPUNIT_TEST(testShrinkPadding);
|
||||
CPPUNIT_TEST(testEmptyFrame);
|
||||
CPPUNIT_TEST(testSkipUnreadableFrame);
|
||||
CPPUNIT_TEST(testDuplicateTags);
|
||||
CPPUNIT_TEST(testParseTOCFrameWithManyChildren);
|
||||
CPPUNIT_TEST(testInvalidID3v2Version);
|
||||
@@ -1877,6 +1880,52 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testSkipUnreadableFrame()
|
||||
{
|
||||
const auto frame = [](const ByteVector &id, const ByteVector &text) {
|
||||
const ByteVector body = ByteVector(1, '\0') + text;
|
||||
return id + ID3v2::SynchData::fromUInt(body.size()) + ByteVector(2, '\0') + body;
|
||||
};
|
||||
const auto writeTag = [](const string &name, const ByteVector &frames) {
|
||||
{
|
||||
MPEG::File f(name.c_str());
|
||||
f.strip();
|
||||
}
|
||||
FileStream stream(name.c_str());
|
||||
stream.insert(ByteVector("ID3\x04\x00\x00", 6) + ID3v2::SynchData::fromUInt(frames.size()) + frames,
|
||||
0, 0);
|
||||
};
|
||||
|
||||
ScopedFileCopy copy("xing", ".mp3");
|
||||
string newname = copy.fileName();
|
||||
|
||||
// An invalid ID and a v2.2 ID padded with a space, each followed by a
|
||||
// valid frame, are skipped, and the frames after them read and saved.
|
||||
writeTag(newname, frame("TIT2", "Title") + frame("\xff" "LEN", "1") +
|
||||
frame("TPE1", "Artist") + frame("CM1 ", "x") + frame("TALB", "Album"));
|
||||
for(int pass = 0; pass < 2; ++pass) {
|
||||
MPEG::File f(newname.c_str());
|
||||
ID3v2::Tag *tag = f.ID3v2Tag();
|
||||
CPPUNIT_ASSERT_EQUAL(3U, tag->frameList().size());
|
||||
CPPUNIT_ASSERT_EQUAL(String("Title"), tag->title());
|
||||
CPPUNIT_ASSERT_EQUAL(String("Artist"), tag->artist());
|
||||
CPPUNIT_ASSERT_EQUAL(String("Album"), tag->album());
|
||||
if(pass == 0)
|
||||
CPPUNIT_ASSERT(f.save());
|
||||
}
|
||||
|
||||
// A frame followed by anything else still ends the tag.
|
||||
writeTag(newname, frame("TIT2", "Title") + frame("\xff" "LEN", "1") +
|
||||
ByteVector("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a", 10) +
|
||||
frame("TALB", "Album"));
|
||||
{
|
||||
MPEG::File f(newname.c_str());
|
||||
ID3v2::Tag *tag = f.ID3v2Tag();
|
||||
CPPUNIT_ASSERT_EQUAL(1U, tag->frameList().size());
|
||||
CPPUNIT_ASSERT_EQUAL(String("Title"), tag->title());
|
||||
}
|
||||
}
|
||||
|
||||
void testDuplicateTags()
|
||||
{
|
||||
ScopedFileCopy copy("duplicate_id3v2", ".mp3");
|
||||
|
||||
Reference in New Issue
Block a user