TableOfContents and ChapterFrame can be added to v2.3 or v2.4 tags

This commit is contained in:
Scott Wheeler 2014-09-25 19:32:53 +02:00
parent d52baafa24
commit c4c4a28daa
6 changed files with 65 additions and 57 deletions

View File

@ -36,11 +36,13 @@ using namespace ID3v2;
class ChapterFrame::ChapterFramePrivate
{
public:
ChapterFramePrivate()
ChapterFramePrivate() :
tagHeader(0)
{
embeddedFrameList.setAutoDelete(true);
}
const ID3v2::Header *tagHeader;
ByteVector elementID;
uint startTime;
uint endTime;
@ -54,10 +56,11 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
ChapterFrame::ChapterFrame(const ByteVector &data) :
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
@ -228,9 +231,8 @@ void ChapterFrame::parseFields(const ByteVector &data)
d->endOffset = data.toUInt32BE(pos);
pos += 4;
size -= pos;
while(embPos < size - Frame::headerSize(4))
{
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos));
while(embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
if(!frame)
return;
@ -241,7 +243,7 @@ void ChapterFrame::parseFields(const ByteVector &data)
return;
}
embPos += frame->size() + Frame::headerSize(4);
embPos += frame->size() + header()->size();
addEmbeddedFrame(frame);
}
}
@ -262,9 +264,10 @@ ByteVector ChapterFrame::renderFields() const
return data;
}
ChapterFrame::ChapterFrame(const ByteVector &data, Header *h) :
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
Frame(h)
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@ -47,9 +47,10 @@ namespace TagLib {
public:
/*!
* Creates a chapter frame based on \a data.
* Creates a chapter frame based on \a data. \a tagHeader is required as
* the internal frames are parsed based on the tag version.
*/
ChapterFrame(const ByteVector &data);
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*!
* Creates a chapter frame with the element ID \a eID,
@ -229,11 +230,10 @@ namespace TagLib {
virtual ByteVector renderFields() const;
private:
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
ChapterFrame(const ChapterFrame &);
ChapterFrame &operator=(const ChapterFrame &);
ChapterFrame(const ByteVector &data, Header *h);
class ChapterFramePrivate;
ChapterFramePrivate *d;
};

View File

@ -35,11 +35,13 @@ using namespace ID3v2;
class TableOfContentsFrame::TableOfContentsFramePrivate
{
public:
TableOfContentsFramePrivate()
TableOfContentsFramePrivate() :
tagHeader(0)
{
embeddedFrameList.setAutoDelete(true);
}
const ID3v2::Header *tagHeader;
ByteVector elementID;
bool isTopLevel;
bool isOrdered;
@ -52,7 +54,7 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &data) :
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
{
d = new TableOfContentsFramePrivate;
@ -248,9 +250,8 @@ void TableOfContentsFrame::parseFields(const ByteVector &data)
}
size -= pos;
while((uint)embPos < size - Frame::headerSize(4))
{
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos));
while(embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
if(!frame)
return;
@ -261,7 +262,7 @@ void TableOfContentsFrame::parseFields(const ByteVector &data)
return;
}
embPos += frame->size() + Frame::headerSize(4);
embPos += frame->size() + header()->size();
addEmbeddedFrame(frame);
}
}
@ -290,9 +291,11 @@ ByteVector TableOfContentsFrame::renderFields() const
return data;
}
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &data, Header *h) :
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
const ByteVector &data, Header *h) :
Frame(h)
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@ -46,9 +46,10 @@ namespace TagLib {
public:
/*!
* Creates a table of contents frame based on \a data.
* Creates a table of contents frame based on \a data. \a tagHeader is
* required as the internal frames are parsed based on the tag version.
*/
TableOfContentsFrame(const ByteVector &data);
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*!
* Creates a table of contents frame with the element ID \a eID,
@ -60,39 +61,39 @@ namespace TagLib {
* Destroys the frame.
*/
~TableOfContentsFrame();
/*!
* Returns the elementID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
*
*
* \see setElementID()
*/
ByteVector elementID() const;
/*!
* Returns true, if the frame is top-level (doen't have
* any parent CTOC frame).
*
*
* \see setIsTopLevel()
*/
bool isTopLevel() const;
/*!
* Returns true, if the child elements list entries
* are ordered.
*
*
* \see setIsOrdered()
*/
bool isOrdered() const;
/*!
* Returns count of child elements of the frame. It allways
* corresponds to size of child elements list.
*
*
* \see childElements()
*/
uint entryCount() const;
/*!
* Returns list of child elements of the frame.
*
@ -103,55 +104,55 @@ namespace TagLib {
/*!
* Sets the elementID of the frame to \a eID. If \a eID isn't
* null terminated, a null char is appended automatically.
*
*
* \see elementID()
*/
void setElementID(const ByteVector &eID);
/*!
* Sets, if the frame is top-level (doen't have
* any parent CTOC frame).
*
*
* \see isTopLevel()
*/
void setIsTopLevel(const bool &t);
/*!
* Sets, if the child elements list entries
* are ordered.
*
*
* \see isOrdered()
*/
void setIsOrdered(const bool &o);
/*!
* Sets list of child elements of the frame to \a l.
*
* \see childElements()
*/
void setChildElements(const ByteVectorList &l);
/*!
* Adds \a cE to list of child elements of the frame.
*
* \see childElements()
*/
void addChildElement(const ByteVector &cE);
/*!
* Removes \a cE to list of child elements of the frame.
*
* \see childElements()
*/
void removeChildElement(const ByteVector &cE);
/*!
* Returns a reference to the frame list map. This is an FrameListMap of
* all of the frames embedded in the CTOC frame.
*
* This is the most convenient structure for accessing the CTOC frame's
* embedded frames. Many frame types allow multiple instances of the same
* frame type so this is a map of lists. In most cases however there will
* This is the most convenient structure for accessing the CTOC frame's
* embedded frames. Many frame types allow multiple instances of the same
* frame type so this is a map of lists. In most cases however there will
* only be a single frame of a certain type.
*
* \warning You should not modify this data structure directly, instead
@ -160,13 +161,13 @@ namespace TagLib {
* \see embeddedFrameList()
*/
const FrameListMap &embeddedFrameListMap() const;
/*!
* Returns a reference to the embedded frame list. This is an FrameList
* Returns a reference to the embedded frame list. This is an FrameList
* of all of the frames embedded in the CTOC frame in the order that they
* were parsed.
*
* This can be useful if for example you want iterate over the CTOC frame's
* This can be useful if for example you want iterate over the CTOC frame's
* embedded frames in the order that they occur in the CTOC frame.
*
* \warning You should not modify this data structure directly, instead
@ -175,7 +176,7 @@ namespace TagLib {
const FrameList &embeddedFrameList() const;
/*!
* Returns the embedded frame list for frames with the id \a frameID
* Returns the embedded frame list for frames with the id \a frameID
* or an empty list if there are no embedded frames of that type. This
* is just a convenience and is equivalent to:
*
@ -188,7 +189,7 @@ namespace TagLib {
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*!
* Add an embedded frame to the CTOC frame. At this point the CTOC frame
* Add an embedded frame to the CTOC frame. At this point the CTOC frame
* takes ownership of the embedded frame and will handle freeing its memory.
*
* \note Using this method will invalidate any pointers on the list
@ -197,7 +198,7 @@ namespace TagLib {
void addEmbeddedFrame(Frame *frame);
/*!
* Remove an embedded frame from the CTOC frame. If \a del is true the frame's
* Remove an embedded frame from the CTOC frame. If \a del is true the frame's
* memory will be freed; if it is false, it must be deleted by the user.
*
* \note Using this method will invalidate any pointers on the list
@ -206,7 +207,7 @@ namespace TagLib {
void removeEmbeddedFrame(Frame *frame, bool del = true);
/*!
* Remove all embedded frames of type \a id from the CTOC frame and free their
* Remove all embedded frames of type \a id from the CTOC frame and free their
* memory.
*
* \note Using this method will invalidate any pointers on the list
@ -220,16 +221,16 @@ namespace TagLib {
/*!
* CTOC frames each have a unique element ID. This searches for a CTOC
* frame with the element ID \a eID and returns a pointer to it. This
* frame with the element ID \a eID and returns a pointer to it. This
* can be used to link together parent and child CTOC frames.
*
* \see elementID()
*/
static TableOfContentsFrame *findByElementID(const Tag *tag, const ByteVector &eID);
/*!
* CTOC frames each contain a flag that indicates, if CTOC frame is top-level (there isn't
* any frame, which contains this frame in its child elements list). Only a single frame
* any frame, which contains this frame in its child elements list). Only a single frame
* within tag can be top-level. This searches for a top-level CTOC frame.
*
* \see isTopLevel()
@ -241,11 +242,10 @@ namespace TagLib {
virtual ByteVector renderFields() const;
private:
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
TableOfContentsFrame(const TableOfContentsFrame &);
TableOfContentsFrame &operator=(const TableOfContentsFrame &);
TableOfContentsFrame(const ByteVector &data, Header *h);
class TableOfContentsFramePrivate;
TableOfContentsFramePrivate *d;
};

View File

@ -280,12 +280,12 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
// Chapter (ID3v2 chapters 1.0)
if(frameID == "CHAP")
return new ChapterFrame(data, header);
return new ChapterFrame(tagHeader, data, header);
// Table of contents (ID3v2 chapters 1.0)
if(frameID == "CTOC")
return new TableOfContentsFrame(data, header);
return new TableOfContentsFrame(tagHeader, data, header);
return new UnknownFrame(data, header);
}

View File

@ -891,6 +891,7 @@ public:
void testParseChapterFrame()
{
ID3v2::ChapterFrame f(
new ID3v2::Header,
ByteVector("CHAP" // Frame ID
"\x00\x00\x00\x20" // Frame size
"\x00\x00" // Frame flags
@ -917,7 +918,7 @@ public:
void testRenderChapterFrame()
{
ID3v2::ChapterFrame f("CHAP");
ID3v2::ChapterFrame f(new ID3v2::Header, "CHAP");
f.setElementID(ByteVector("\x43\x00", 2));
f.setStartTime(3);
f.setEndTime(5);
@ -946,6 +947,7 @@ public:
void testParseTableOfContentsFrame()
{
ID3v2::TableOfContentsFrame f(
new ID3v2::Header,
ByteVector("CTOC" // Frame ID
"\x00\x00\x00\x16" // Frame size
"\x00\x00" // Frame flags
@ -975,7 +977,7 @@ public:
void testRenderTableOfContentsFrame()
{
ID3v2::TableOfContentsFrame f("CTOC");
ID3v2::TableOfContentsFrame f(new ID3v2::Header, "CTOC");
f.setElementID(ByteVector("\x54\x00", 2));
f.setIsTopLevel(false);
f.setIsOrdered(true);