]> granicus.if.org Git - taglib/commitdiff
APE-tags for mp3s.
authorAllan Sandfeld Jensen <kde@carewolf.com>
Sun, 15 Aug 2004 21:14:12 +0000 (21:14 +0000)
committerAllan Sandfeld Jensen <kde@carewolf.com>
Sun, 15 Aug 2004 21:14:12 +0000 (21:14 +0000)
Currently they are for special purposes only, and thus not used as a part
of the union tag.

git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@338184 283d02a7-25f6-0310-bc7c-ecb5cbfe19da

mpeg/Makefile.am
mpeg/mpegfile.cpp
mpeg/mpegfile.h

index cbec23c323549f17f516c8f09b5620e60ff262ff..acc3614ea88b67097a18d802a18678b8ce5af484 100644 (file)
@@ -2,6 +2,7 @@ SUBDIRS = id3v1 id3v2
 INCLUDES = \
        -I$(top_srcdir)/taglib\
        -I$(top_srcdir)/taglib/toolkit \
+        -I$(top_srcdir)/taglib/ape \
        -I$(top_srcdir)/taglib/mpeg/id3v2 -I./id3v2 \
        -I$(top_srcdir)/taglib/mpeg/id3v1 -I./id3v1 \
        $(all_includes)
index 3ecc16254be0f2f724ca20b85c9de4a5fd8d73c5..4f2da52137dd555e631f622bf3484c3fd72a25ab 100644 (file)
@@ -22,6 +22,8 @@
 #include <id3v2tag.h>
 #include <id3v2header.h>
 #include <id3v1tag.h>
+#include <apefooter.h>
+#include <apetag.h>
 #include <tdebug.h>
 
 #include <bitset>
@@ -172,11 +174,15 @@ public:
     ID3v2Tag(0),
     ID3v2Location(-1),
     ID3v2OriginalSize(0),
+    APETag(0),
+    APELocation(-1),
+    APEOriginalSize(0),
     ID3v1Tag(0),
     ID3v1Location(-1),
     tag(0),
     hasID3v2(false),
     hasID3v1(false),
+    hasAPE(false),
     properties(0) {}
 
   ~FilePrivate() {
@@ -191,16 +197,21 @@ public:
   long ID3v2Location;
   uint ID3v2OriginalSize;
 
+  APE::Tag *APETag;
+  long APELocation;
+  uint APEOriginalSize;
+
   ID3v1::Tag *ID3v1Tag;
   long ID3v1Location;
 
   MPEGTag *tag;
 
-  // These indicate whether the file *on disk* has an ID3v[1/2] tag, not if
+  // These indicate whether the file *on disk* has these tags, not if
   // this data structure does.  This is used in computing offsets.
 
   bool hasID3v2;
   bool hasID3v1;
+  bool hasAPE;
 
   Properties *properties;
 };
@@ -247,7 +258,7 @@ MPEG::Properties *MPEG::File::audioProperties() const
 
 bool MPEG::File::save()
 {
-  return save(ID3v1 | ID3v2);
+  return save(AllTags);
 }
 
 bool MPEG::File::save(int tags)
@@ -255,9 +266,9 @@ bool MPEG::File::save(int tags)
   if(tags == NoTags)
     return strip(AllTags);
 
-  if(!d->ID3v2Tag && !d->ID3v1Tag) {
+  if(!d->ID3v2Tag && !d->ID3v1Tag && !d->APETag) {
 
-    if(d->hasID3v1 || d->hasID3v2)
+    if(d->hasID3v1 || d->hasID3v2 || d->hasAPE)
       return strip(AllTags);
 
     return true;
@@ -271,10 +282,10 @@ bool MPEG::File::save(int tags)
   // Create the tags if we've been asked to.  Copy the values from the tag that
   // does exist into the new tag.
 
-  if(tags & ID3v2 && d->ID3v1Tag)
+  if((tags & ID3v2) && d->ID3v1Tag)
     Tag::duplicate(d->ID3v1Tag, ID3v2Tag(true), false);
 
-  if(tags & ID3v1 && d->ID3v2Tag)
+  if((tags & ID3v1) && d->ID3v2Tag)
     Tag::duplicate(d->ID3v2Tag, ID3v1Tag(true), false);
 
   bool success = true;
@@ -306,6 +317,30 @@ bool MPEG::File::save(int tags)
   else if(d->hasID3v1)
     success = strip(ID3v1, false) && success;
 
+  // Dont save an APE-tag unless one has been created
+  if((APE & tags) && d->APETag) {
+    if(d->hasAPE)
+      insert(d->APETag->render(), d->APELocation, d->APEOriginalSize);
+    else {
+      if(d->hasID3v1)  {
+        insert(d->APETag->render(), d->ID3v1Location, 0);
+        d->APEOriginalSize = d->APETag->footer()->completeTagSize();
+        d->hasAPE = true;
+        d->APELocation = d->ID3v1Location;
+        d->ID3v1Location += d->APEOriginalSize;
+      }
+      else {
+        seek(0, End);
+        d->APELocation = tell();
+        writeBlock(d->APETag->render());
+        d->APEOriginalSize = d->APETag->footer()->completeTagSize();
+        d->hasAPE = true;
+      }
+    }
+  }
+  else if(d->hasAPE)
+    success = strip(APE, false) && success;
+
   return success;
 }
 
@@ -331,6 +366,17 @@ ID3v1::Tag *MPEG::File::ID3v1Tag(bool create)
   return d->ID3v1Tag;
 }
 
+APE::Tag *MPEG::File::APETag(bool create)
+{
+  if(!create || d->APETag)
+    return d->APETag;
+
+  // no APE tag exists and we've been asked to create one
+
+  d->APETag = new APE::Tag;
+  return d->APETag;
+}
+
 bool MPEG::File::strip(int tags)
 {
   return strip(tags, true);
@@ -343,7 +389,7 @@ bool MPEG::File::strip(int tags, bool freeMemory)
     return false;
   }
 
-  if(tags & ID3v2 && d->hasID3v2) {
+  if((tags & ID3v2) && d->hasID3v2) {
     removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
     d->ID3v2Location = -1;
     d->ID3v2OriginalSize = 0;
@@ -358,7 +404,7 @@ bool MPEG::File::strip(int tags, bool freeMemory)
       d->ID3v1Location = findID3v1();
   }
 
-  if(tags & ID3v1 && d->hasID3v1) {
+  if((tags & ID3v1) && d->hasID3v1) {
     truncate(d->ID3v1Location);
     d->ID3v1Location = -1;
     d->hasID3v1 = false;
@@ -368,6 +414,20 @@ bool MPEG::File::strip(int tags, bool freeMemory)
     }
   }
 
+  if((tags & APE) && d->hasAPE) {
+    removeBlock(d->APELocation, d->APEOriginalSize);
+    d->APELocation = -1;
+    d->hasAPE = false;
+    if(d->hasID3v1) {
+      if (d->ID3v1Location > d->APELocation)
+        d->ID3v1Location -= d->APEOriginalSize;
+    }
+    if(freeMemory) {
+      delete d->APETag;
+      d->APETag = 0;
+    }
+  }
+
   return true;
 }
 
@@ -468,6 +528,19 @@ void MPEG::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
     d->hasID3v1 = true;
   }
 
+  // Look for an APE tag
+
+  d->APELocation = findAPE();
+
+  if(d->APELocation >= 0) {
+
+    d->APETag = new APE::Tag(this, d->APELocation);
+
+    d->APEOriginalSize = d->APETag->footer()->completeTagSize();
+
+    d->hasAPE = true;
+  }
+
   if(readProperties)
     d->properties = new Properties(this, propertiesStyle);
 }
@@ -595,6 +668,22 @@ long MPEG::File::findID3v1()
   return -1;
 }
 
+long MPEG::File::findAPE()
+{
+  if(isValid()) {
+    if (d->hasID3v1)
+        seek(-160, End);
+    else
+        seek(-32, End);
+
+    long p = tell();
+
+    if(readBlock(8) == APE::Tag::fileIdentifier())
+      return p;
+  }
+  return -1;
+}
+
 bool MPEG::File::secondSynchByte(char byte)
 {
   if(uchar(byte) == 0xff)
index 334b58d1dd1b09da671bce99de7be94f16482b34..431523e08746036d70885032535b16bd3d4ed641 100644 (file)
@@ -30,6 +30,7 @@ namespace TagLib {
 
   namespace ID3v2 { class Tag; class FrameFactory; }
   namespace ID3v1 { class Tag; }
+  namespace APE { class Tag; }
 
   //! An implementation of TagLib::File with MPEG (MP3) specific methods
 
@@ -57,6 +58,8 @@ namespace TagLib {
         ID3v1   = 0x0001,
         //! Matches ID3v2 tags.
         ID3v2   = 0x0002,
+        //! Matches APE tags.
+        APE     = 0x0004,
         //! Matches all tag types.
         AllTags = 0xffff
       };
@@ -103,6 +106,7 @@ namespace TagLib {
        *
        * \see ID3v1Tag()
        * \see ID3v2Tag()
+       * \see APETag()
        */
       virtual Tag *tag() const;
 
@@ -166,6 +170,19 @@ namespace TagLib {
        */
       ID3v1::Tag *ID3v1Tag(bool create = false);
 
+      /*!
+       * Returns a pointer to the APE tag of the file.
+       *
+       * If \a create is false (the default) this will return a null pointer
+       * if there is no valid APE tag.  If \a create is true it will create
+       * an APE tag if one does not exist.
+       *
+       * \note The Tag <b>is still</b> owned by the MPEG::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      APE::Tag *APETag(bool create = false);
+
       /*!
        * This will strip the tags that match the OR-ed together TagTypes from the
        * file.  By default it strips all tags.  It returns true if the tags are
@@ -173,7 +190,7 @@ namespace TagLib {
        *
        * This is equivalent to strip(tags, true)
        *
-       * \note This will also invalidate pointers to the ID3v2 and ID3v1 tags
+       * \note This will also invalidate pointers to the ID3 and APE tags
        * as their memory will be freed.
        */
       bool strip(int tags = AllTags);
@@ -183,7 +200,7 @@ namespace TagLib {
        * file.  By default it strips all tags.  It returns true if the tags are
        * successfully stripped.
        *
-       * If \a freeMemory is true the ID3v1 and ID3v2 tags will be deleted and
+       * If \a freeMemory is true the ID3 and APE tags will be deleted and
        * pointers to them will be invalidated.
        */
       // BIC: merge with the method above
@@ -225,6 +242,7 @@ namespace TagLib {
       void read(bool readProperties, Properties::ReadStyle propertiesStyle);
       long findID3v2();
       long findID3v1();
+      long findAPE();
 
       /*!
        * MPEG frames can be recognized by the bit pattern 11111111 111, so the