diff --git a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp index 4c750cc5..550df64e 100644 --- a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp +++ b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp @@ -50,6 +50,31 @@ public: FrameList embeddedFrameList; }; +namespace { + + // These functions are needed to try to aim for backward compatibility with + // an API that previously (unreasonably) required null bytes to be appeneded + // at the end of identifiers explicitly by the API user. + + // BIC: remove these + + ByteVector &strip(ByteVector &b) + { + if(b.endsWith('\0')) + b.resize(b.size() - 1); + return b; + } + + ByteVectorList &strip(ByteVectorList &l) + { + for(ByteVectorList::Iterator it = l.begin(); it != l.end(); ++it) + { + strip(*it); + } + return l; + } +} + //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// @@ -68,6 +93,7 @@ TableOfContentsFrame::TableOfContentsFrame(const ByteVector &eID, const ByteVect { d = new TableOfContentsFramePrivate; d->elementID = eID; + strip(d->elementID); d->childElements = ch; FrameList l = eF; for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) @@ -107,8 +133,7 @@ ByteVectorList TableOfContentsFrame::childElements() const void TableOfContentsFrame::setElementID(const ByteVector &eID) { d->elementID = eID; - if(eID.at(eID.size() - 1) != char(0)) - d->elementID.append(char(0)); + strip(d->elementID); } void TableOfContentsFrame::setIsTopLevel(const bool &t) @@ -124,16 +149,22 @@ void TableOfContentsFrame::setIsOrdered(const bool &o) void TableOfContentsFrame::setChildElements(const ByteVectorList &l) { d->childElements = l; + strip(d->childElements); } void TableOfContentsFrame::addChildElement(const ByteVector &cE) { d->childElements.append(cE); + strip(d->childElements); } void TableOfContentsFrame::removeChildElement(const ByteVector &cE) { ByteVectorList::Iterator it = d->childElements.find(cE); + + if(it == d->childElements.end()) + it = d->childElements.find(cE + ByteVector("\0")); + d->childElements.erase(it); } @@ -240,17 +271,19 @@ void TableOfContentsFrame::parseFields(const ByteVector &data) int pos = 0; TagLib::uint embPos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); - d->elementID.append(char(0)); d->isTopLevel = (data.at(pos) & 2) > 0; d->isOrdered = (data.at(pos++) & 1) > 0; TagLib::uint entryCount = data.at(pos++); for(TagLib::uint i = 0; i < entryCount; i++) { ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); - childElementID.append(char(0)); d->childElements.append(childElementID); } size -= pos; + + if(size < header()->size()) + return; + while(embPos < size - header()->size()) { Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader); @@ -273,6 +306,7 @@ ByteVector TableOfContentsFrame::renderFields() const ByteVector data; data.append(d->elementID); + data.append('\0'); char flags = 0; if(d->isTopLevel) flags += 2; @@ -283,6 +317,7 @@ ByteVector TableOfContentsFrame::renderFields() const ByteVectorList::ConstIterator it = d->childElements.begin(); while(it != d->childElements.end()) { data.append(*it); + data.append('\0'); it++; } FrameList l = d->embeddedFrameList; diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index be16fd0b..c2609cab 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -1001,25 +1001,22 @@ public: ByteVector("CTOC" // Frame ID "\x00\x00\x00\x16" // Frame size "\x00\x00" // Frame flags - "\x54\x00" // Element ID + "\x54\x00" // Element ID ("T") "\x01" // CTOC flags "\x02" // Entry count - "\x43\x00" // First entry - "\x44\x00" // Second entry + "\x43\x00" // First entry ("C") + "\x44\x00" // Second entry ("D") "TIT2" // Embedded frame ID "\x00\x00\x00\x04" // Embedded frame size "\x00\x00" // Embedded frame flags "\x00" // TIT2 frame text encoding "TC1", 32)); // Table of contents title - CPPUNIT_ASSERT_EQUAL(ByteVector("\x54\x00", 2), - f.elementID()); + CPPUNIT_ASSERT_EQUAL(ByteVector("T"), f.elementID()); CPPUNIT_ASSERT(!f.isTopLevel()); CPPUNIT_ASSERT(f.isOrdered()); CPPUNIT_ASSERT((uint)0x02 == f.entryCount()); - CPPUNIT_ASSERT_EQUAL(ByteVector("\x43\x00", 2), - f.childElements()[0]); - CPPUNIT_ASSERT_EQUAL(ByteVector("\x44\x00", 2), - f.childElements()[1]); + CPPUNIT_ASSERT_EQUAL(ByteVector("C"), f.childElements()[0]); + CPPUNIT_ASSERT_EQUAL(ByteVector("D"), f.childElements()[1]); CPPUNIT_ASSERT((uint)0x01 == f.embeddedFrameList().size()); CPPUNIT_ASSERT(f.embeddedFrameList("TIT2").size() == 1); CPPUNIT_ASSERT(f.embeddedFrameList("TIT2")[0]->toString() == "TC1");