mirror of
https://github.com/taglib/taglib.git
synced 2025-06-04 01:28:21 -04:00
TableOfContents and ChapterFrame can be added to v2.3 or v2.4 tags
This commit is contained in:
parent
d52baafa24
commit
c4c4a28daa
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user