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
////////////////////////////////////////////////////////////////////////////////
{
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)
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)
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);
}
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);
ByteVector data;
data.append(d->elementID);
+ data.append('\0');
char flags = 0;
if(d->isTopLevel)
flags += 2;
ByteVectorList::ConstIterator it = d->childElements.begin();
while(it != d->childElements.end()) {
data.append(*it);
+ data.append('\0');
it++;
}
FrameList l = d->embeddedFrameList;
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");