]> granicus.if.org Git - taglib/commitdiff
Finished parseFields, renderFields and asProperty methods of ChapterFrame and TableOf...
authorLukáš Krejčí <krejclu6@fel.cvut.cz>
Sun, 21 Apr 2013 14:16:57 +0000 (16:16 +0200)
committerLukáš Krejčí <krejclu6@fel.cvut.cz>
Sun, 21 Apr 2013 14:16:57 +0000 (16:16 +0200)
Methods setElementID of ChapterFrame and TableOfContentsFrame classes now automatically terminates new element ID with null.

taglib/mpeg/id3v2/frames/chapterframe.cpp
taglib/mpeg/id3v2/frames/chapterframe.h
taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
taglib/mpeg/id3v2/frames/tableofcontentsframe.h
taglib/mpeg/id3v2/id3v2framefactory.cpp

index 1474db1ac18c77a6d4712c516ab568a2b6759620..633a6d8b03c39e8cbb0a19e99df0f13c88877dcd 100644 (file)
@@ -98,6 +98,8 @@ uint ChapterFrame::endOffset() const
 void ChapterFrame::setElementID(const ByteVector &eID)
 {
   d->elementID = eID;
+  if(eID.at(eID.size() - 1) != char(0))
+    d->elementID.append(char(0));
 }
 
 void ChapterFrame::setStartTime(const uint &sT)
@@ -120,21 +122,17 @@ void ChapterFrame::setEndOffset(const uint &eO)
   d->endOffset = eO;
 }
 
-String UniqueFileIdentifierFrame::toString() const
+String ChapterFrame::toString() const
 {
   return String::null;
 }
 
-PropertyMap ChapterFrame::asProperties() const
+PropertyMap UniqueFileIdentifierFrame::asProperties() const
 {
-  //DODELAT
   PropertyMap map;
-  if(d->owner == "http://musicbrainz.org") {
-    map.insert("MUSICBRAINZ_TRACKID", String(d->identifier));
-  }
-  else {
-    map.unsupportedData().append(frameID() + String("/") + d->owner);
-  }
+
+  map.unsupportedData().append(frameID() + String("/") + d->elementID);
+  
   return map;
 }
 
@@ -156,25 +154,32 @@ ChapterFrame *ChapterFrame::findByElementID(const Tag *tag, const ByteVector &eI
 
 void ChapterFrame::parseFields(const ByteVector &data)
 {
-  //DODELAT
-  if(data.size() < 1) {
-    debug("An UFID frame must contain at least 1 byte.");
+  if(data.size() < 18) {
+    debug("An CHAP frame must contain at least 18 bytes (1 byte element ID terminated by null and 4x4 bytes for start and end time and offset).");
     return;
   }
 
   int pos = 0;
-  d->owner = readStringField(data, String::Latin1, &pos);
-  d->identifier = data.mid(pos);
+  d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
+  d->elementID.append(char(0));
+  d->startTime = data.mid(pos, 4).toUInt(true);
+  pos += 4;
+  d->endTime = data.mid(pos, 4).toUInt(true);
+  pos += 4;
+  d->startOffset = data.mid(pos, 4).toUInt(true);
+  pos += 4;
+  d->endOffset = data.mid(pos, 4).toUInt(true);
 }
 
 ByteVector ChapterFrame::renderFields() const
 {
-  //DODELAT
   ByteVector data;
 
-  data.append(d->owner.data(String::Latin1));
-  data.append(char(0));
-  data.append(d->identifier);
+  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));
 
   return data;
 }
index ce9096cf2b883405b6a14c0f8f05fe0e42895bfb..1ecbbbfd95497c850ac42d3007e69e4862b1949e 100644 (file)
@@ -62,7 +62,7 @@ namespace TagLib {
       ~ChapterFrame();
       
       /*!
-       * Returns the elementID of the frame. Element ID
+       * Returns the element ID of the frame. Element ID
        * is a null terminated string, however it's not human-readable.
        * 
        * \see setElementID()
@@ -100,9 +100,9 @@ namespace TagLib {
       uint endOffset() const;
 
       /*!
-       * Sets the elementID of the frame to \a eID. 
+       * Sets the element ID of the frame to \a eID. If \a eID isn't
+       * null terminated, a null char is appended automatically.
        * 
-       * \warning Element ID must be null terminated.
        * \see elementID()
        */
       void setElementID(const ByteVector &eID);
index 1cb24b50f262b466fd4b8cdabdfdc85faafd1836..39df25d62e41f95ee74444340557039f30740d09 100644 (file)
@@ -81,9 +81,9 @@ bool TableOfContentsFrame::isOrdered() const
   return d->isOrdered;
 }
 
-unsigned char TableOfContentsFrame::entryCount() const
+uint TableOfContentsFrame::entryCount() const
 {
-  return (unsigned char)(d->childElements.size());
+  return d->childElements.size();
 }
 
 ByteVectorList TableOfContentsFrame::childElements const
@@ -94,6 +94,8 @@ 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));
 }
 
 void TableOfContentsFrame::setIsTopLevel(const bool &t)
@@ -118,23 +120,19 @@ String TableOfContentsFrame::toString() const
 
 PropertyMap TableOfContentsFrame::asProperties() const
 {
-  //DODELAT
   PropertyMap map;
-  if(d->owner == "http://musicbrainz.org") {
-    map.insert("MUSICBRAINZ_TRACKID", String(d->identifier));
-  }
-  else {
-    map.unsupportedData().append(frameID() + String("/") + d->owner);
-  }
+
+  map.unsupportedData().append(frameID() + String("/") + d->elementID);
+  
   return map;
 }
 
 TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
 {
-  ID3v2::FrameList comments = tag->frameList("CTOC");
+  ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
 
-  for(ID3v2::FrameList::ConstIterator it = comments.begin();
-      it != comments.end();
+  for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
+      it != tablesOfContents.end();
       ++it)
   {
     TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
@@ -145,28 +143,63 @@ TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *ta
   return 0;
 }
 
+TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const Tag *tag) // static
+{
+  ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
+
+  for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
+      it != tablesOfContents.end();
+      ++it)
+  {
+    TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
+    if(frame && frame->isTopLevel() == true)
+      return frame;
+  }
+
+  return 0;
+}
+
 void TableOfContentsFrame::parseFields(const ByteVector &data)
 {
-  //DODELAT
-  if(data.size() < 1) {
-    debug("An UFID frame must contain at least 1 byte.");
+  if(data.size() < 6) {
+    debug("An CTOC frame must contain at least 6 bytes (1 byte element ID terminated by null, 1 byte flags, 1 byte entry count and 1 byte child element ID terminated by null.");
     return;
   }
 
   int pos = 0;
-  d->owner = readStringField(data, String::Latin1, &pos);
-  d->identifier = data.mid(pos);
+  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;
+  uint entryCount = data.at(pos++);
+  for(int i = 0; i < entryCount; i++)
+  {
+    ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
+    childElementID.append(char(0));
+    d->childElements.append(childElementID);
+  }
 }
 
 ByteVector TableOfContentsFrame::renderFields() const
 {
-  //DODELAT
   ByteVector data;
 
-  data.append(d->owner.data(String::Latin1));
+  data.append(d->elementID);
   data.append(char(0));
-  data.append(d->identifier);
-
+  char flags = 0;
+  if(d->isTopLevel)
+    flags += 2;
+  if(d->isOrdered)
+    flags += 1;
+  data.append(flags);
+  data.append((char)(entryCount()));
+  ConstIterator it = d->childElements.begin();
+  while(it != d->childElements.end()) {
+    data.append(*it);
+    data.append(char(0));
+    it++;
+  }
+  
   return data;
 }
 
index 0d189dfccd04e33c24ad995db759af1a53431bca..63ab96eeb202ef2e07c1628fdfdc71911e06ea20 100644 (file)
@@ -88,10 +88,9 @@ namespace TagLib {
        * Returns count of child elements of the frame. It allways
        * corresponds to size of child elements list.
        * 
-       * \note Return type should be uint8_t, not unsigned char.
        * \see childElements()
        */
-      unsigned char entryCount() const;
+      uint entryCount() const;
       
       /*!
        * Returns list of child elements of the frame.
@@ -101,9 +100,9 @@ namespace TagLib {
       ByteVectorList childElements() const;
 
       /*!
-       * Sets the elementID of the frame to \a eID. 
+       * Sets the elementID of the frame to \a eID. If \a eID isn't
+       * null terminated, a null char is appended automatically.
        * 
-       * \warning Element ID must be null terminated.
        * \see elementID()
        */
       void setElementID(const ByteVector &eID);
@@ -143,6 +142,15 @@ namespace TagLib {
        * \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 
+       * within tag can be top-level. This searches for a top-level CTOC frame.
+       *
+       * \see isTopLevel()
+       */
+      static TableOfContentsFrame *findTopLevel(const Tag *tag);
 
     protected:
       virtual void parseFields(const ByteVector &data);
index c7d7421453b1359376a4cf9f03679f05a4e440d7..05eb7f2138c181d1a04b8428e3a3c280adb448aa 100644 (file)
@@ -45,6 +45,8 @@
 #include "frames/popularimeterframe.h"
 #include "frames/privateframe.h"
 #include "frames/ownershipframe.h"
+#include "frames/chapterframe.h"
+#include "frames/tableofcontentsframe.h"
 
 using namespace TagLib;
 using namespace ID3v2;
@@ -258,6 +260,16 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
     d->setTextEncoding(f);
     return f;
   }
+  
+  // Chapter (ID3v2 chapters 1.0)
+  
+  if(frameID == "CHAP")
+    return new ChapterFrame(data, header);
+  
+  // Table of contents (ID3v2 chapters 1.0)
+  
+  if(frameID == "CTOC")
+    return new TableOfContentsFrame(data, header);
 
   return new UnknownFrame(data, header);
 }