diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index a940caf5..2789f749 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -76,6 +76,8 @@ set(tag_HDRS mpeg/id3v2/frames/unknownframe.h mpeg/id3v2/frames/unsynchronizedlyricsframe.h mpeg/id3v2/frames/urllinkframe.h + mpeg/id3v2/frames/chapterframe.h + mpeg/id3v2/frames/tableofcontentsframe.h ogg/oggfile.h ogg/oggpage.h ogg/oggpageheader.h @@ -166,6 +168,8 @@ set(frames_SRCS mpeg/id3v2/frames/unknownframe.cpp mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp mpeg/id3v2/frames/urllinkframe.cpp + mpeg/id3v2/frames/chapterframe.cpp + mpeg/id3v2/frames/tableofcontentsframe.cpp ) set(ogg_SRCS diff --git a/taglib/mpeg/id3v2/frames/chapterframe.cpp b/taglib/mpeg/id3v2/frames/chapterframe.cpp index 633a6d8b..497f1a41 100644 --- a/taglib/mpeg/id3v2/frames/chapterframe.cpp +++ b/taglib/mpeg/id3v2/frames/chapterframe.cpp @@ -54,7 +54,7 @@ ChapterFrame::ChapterFrame(const ByteVector &data) : setData(data); } -ChapterFrame::ChapterFrame(const ByteVector &eID, const int &sT, const int &eT, const int &sO, const int &eO) : +ChapterFrame::ChapterFrame(const ByteVector &eID, const uint &sT, const uint &eT, const uint &sO, const uint &eO) : ID3v2::Frame("CHAP") { d = new ChapterFramePrivate; @@ -62,7 +62,7 @@ ChapterFrame::ChapterFrame(const ByteVector &eID, const int &sT, const int &eT, d->startTime = sT; d->endTime = eT; d->startOffset = sO; - d->endOffset = e0; + d->endOffset = eO; } ChapterFrame::~ChapterFrame() @@ -127,7 +127,7 @@ String ChapterFrame::toString() const return String::null; } -PropertyMap UniqueFileIdentifierFrame::asProperties() const +PropertyMap ChapterFrame::asProperties() const { PropertyMap map; @@ -176,10 +176,10 @@ ByteVector ChapterFrame::renderFields() const ByteVector data; data.append(d->elementID); - data.append(ByteVector.fromUInt(d->startTime, true)); - data.append(ByteVector.fromUInt(d->endTime, true)); - data.append(ByteVector.fromUInt(d->startOffset, true)); - data.append(ByteVector.fromUInt(d->endOffset, true)); + data.append(ByteVector::fromUInt(d->startTime, true)); + data.append(ByteVector::fromUInt(d->endTime, true)); + data.append(ByteVector::fromUInt(d->startOffset, true)); + data.append(ByteVector::fromUInt(d->endOffset, true)); return data; } diff --git a/taglib/mpeg/id3v2/frames/chapterframe.h b/taglib/mpeg/id3v2/frames/chapterframe.h index 1ecbbbfd..4a53cb57 100644 --- a/taglib/mpeg/id3v2/frames/chapterframe.h +++ b/taglib/mpeg/id3v2/frames/chapterframe.h @@ -27,6 +27,7 @@ #define TAGLIB_CHAPTERFRAME #include "id3v2frame.h" +#include "taglib_export.h" namespace TagLib { @@ -87,6 +88,7 @@ namespace TagLib { * Returns zero based byte offset (count of bytes from the beginning * of the audio file) of chapter's start. * + * \note If returned value is 0xFFFFFFFF, start time should be used instead. * \see setStartOffset() */ uint startOffset() const; @@ -95,6 +97,7 @@ namespace TagLib { * Returns zero based byte offset (count of bytes from the beginning * of the audio file) of chapter's end. * + * \note If returned value is 0xFFFFFFFF, end time should be used instead. * \see setEndOffset() */ uint endOffset() const; @@ -135,7 +138,7 @@ namespace TagLib { * * \see endOffset() */ - void endOffset(const uint &eO); + void setEndOffset(const uint &eO); virtual String toString() const; diff --git a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp index bb43f5a6..1836f721 100644 --- a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp +++ b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp @@ -169,10 +169,10 @@ void TableOfContentsFrame::parseFields(const ByteVector &data) int pos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->elementID.append(char(0)); - d->isTopLevel = (data.at(pos++) & 2) > 0; + d->isTopLevel = (data.at(pos) & 2) > 0; d->isOrdered = (data.at(pos++) & 1) > 0; uint entryCount = data.at(pos++); - for(int i = 0; i < entryCount; i++) + for(uint i = 0; i < entryCount; i++) { ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); childElementID.append(char(0)); @@ -193,7 +193,7 @@ ByteVector TableOfContentsFrame::renderFields() const flags += 1; data.append(flags); data.append((char)(entryCount())); - ConstIterator it = d->childElements.begin(); + ByteVectorList::ConstIterator it = d->childElements.begin(); while(it != d->childElements.end()) { data.append(*it); data.append(char(0)); diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 48faf306..b696a088 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -77,6 +79,8 @@ class TestID3v2 : public CppUnit::TestFixture CPPUNIT_TEST(testPropertyInterface2); CPPUNIT_TEST(testDeleteFrame); CPPUNIT_TEST(testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2); + CPPUNIT_TEST(testChapters); + CPPUNIT_TEST(testTableOfContents); CPPUNIT_TEST_SUITE_END(); public: @@ -734,6 +738,66 @@ public: CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TPE1")); } + void testChaptersParsing() + { + ID3v2::ChapterFrame f( + ByteVector("CHAP" // Frame ID + "\x00\x00\x00\x12" // Frame size + "\x00\x00" // Frame flags + "\x43\x00" // Element ID + "\x00\x00\x00\x03" // Start time + "\x00\x00\x00\x05" // End time + "\x00\x00\x00\x02" // Start offset + "\x00\x00\x00\x03", 28)); // End offset + CPPUNIT_ASSERT_EQUAL(ByteVector("\x43\x00", 2), + f.elementID()); + CPPUNIT_ASSERT((uint)0x03 == f.startTime()); + CPPUNIT_ASSERT((uint)0x05 == f.endTime()); + CPPUNIT_ASSERT((uint)0x02 == f.startOffset()); + CPPUNIT_ASSERT((uint)0x03 == f.endOffset()); + } + + void testChapters() + { + ID3v2::ChapterFrame f( + ByteVector("CHAP" // Frame ID + "\x00\x00\x00\x12" // Frame size + "\x00\x00" // Frame flags + "\x43\x00" // Element ID + "\x00\x00\x00\x03" // Start time + "\x00\x00\x00\x05" // End time + "\x00\x00\x00\x02" // Start offset + "\x00\x00\x00\x03", 28)); // End offset + CPPUNIT_ASSERT_EQUAL(ByteVector("\x43\x00", 2), + f.elementID()); + CPPUNIT_ASSERT((uint)0x03 == f.startTime()); + CPPUNIT_ASSERT((uint)0x05 == f.endTime()); + CPPUNIT_ASSERT((uint)0x02 == f.startOffset()); + CPPUNIT_ASSERT((uint)0x03 == f.endOffset()); + } + + void testTableOfContents() + { + ID3v2::TableOfContentsFrame f( + ByteVector("CTOC" // Frame ID + "\x00\x00\x00\x08" // Frame size + "\x00\x00" // Frame flags + "\x54\x00" // Element ID + "\x01" // CTOC flags + "\x02" // Entry count + "\x43\x00" // First entry + "\x44\x00", 18)); // Second entry + CPPUNIT_ASSERT_EQUAL(ByteVector("\x54\x00", 2), + 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_TEST_SUITE_REGISTRATION(TestID3v2);