Index: configure.in
===================================================================
RCS file: /var/cvs/tunepimp/configure.in,v
retrieving revision 1.36
diff -u -3 -p -r1.36 configure.in
--- configure.in	1 Jul 2004 20:57:57 -0000	1.36
+++ configure.in	5 Aug 2004 01:55:55 -0000
@@ -112,6 +112,38 @@ else
    AC_MSG_RESULT([*** NOT compiling FLAC support])
 fi
 
+
+dnl ---------- TAGLIB CHECK ----------
+
+AC_DEFUN([AC_HAVE_TAGLIB],
+[
+    AC_DEFINE(HAVE_TAGLIB, 1, [have TagLib])
+    taglib_includes=[`$TAGLIB_CONFIG --cflags`]
+    taglib_libs=[`$TAGLIB_CONFIG --libs`]
+    have_taglib=true
+])
+
+AC_DEFUN([AC_NO_TAGLIB],
+[
+    AC_DEFINE(HAVE_TAGLIB, 0, [don't have TagLib])
+    taglib_includes=""
+    taglib_libs=""
+    have_taglib=false
+    AC_MSG_RESULT([*** NOT compiling TagLib support])
+])
+
+AC_PATH_PROG(TAGLIB_CONFIG, taglib-config, [no], [$PATH:$prefix/bin])
+if test "x$TAGLIB_CONFIG" = "xno" ; then
+    AC_NO_TAGLIB
+else
+    AC_HAVE_TAGLIB
+fi
+
+AC_SUBST(taglib_includes)
+AC_SUBST(taglib_libs)
+
+dnl ---------- END TAGLIB CHECK ----------
+
 AC_LANG_SAVE
 AC_LANG_CPLUSPLUS
 AC_CHECK_LIB(musicbrainz, mb_GetVersion,,
Index: include/tunepimp/metadata.h
===================================================================
RCS file: /var/cvs/tunepimp/include/tunepimp/metadata.h,v
retrieving revision 1.4
diff -u -3 -p -r1.4 metadata.h
--- include/tunepimp/metadata.h	9 Jun 2004 20:48:58 -0000	1.4
+++ include/tunepimp/metadata.h	5 Aug 2004 01:55:55 -0000
@@ -28,6 +28,7 @@
 #define __METADATA_H__
 
 #include <string>
+#include <cstdio>
 using namespace std;
 
 #include "defs.h"
Index: plugins/mp3/Makefile.am
===================================================================
RCS file: /var/cvs/tunepimp/plugins/mp3/Makefile.am,v
retrieving revision 1.6
diff -u -3 -p -r1.6 Makefile.am
--- plugins/mp3/Makefile.am	26 May 2004 23:51:51 -0000	1.6
+++ plugins/mp3/Makefile.am	5 Aug 2004 01:55:55 -0000
@@ -24,12 +24,12 @@
 #
 SUBDIRS = id3tag
 
-INCLUDES = -I$(top_srcdir)/include/tunepimp $(INCLTDL) 
+INCLUDES = -I$(top_srcdir)/include/tunepimp $(INCLTDL) $(taglib_includes) 
 
 lib_LTLIBRARIES = mp3.la
 mp3_la_SOURCES = mp3.cpp mp3decode.cpp mp3decode.h id3_meta.cpp
 mp3_la_LDFLAGS = -module -avoid-version
-mp3_la_LIBADD = id3tag/libid3tag.la ../../lib/libpluginsupport.la -lmad -lmusicbrainz
+mp3_la_LIBADD = ../../lib/libpluginsupport.la -lmad -lmusicbrainz $(taglib_libs)
 
 noinst_HEADERS = mp3decode.h id3_meta.h
 
Index: plugins/mp3/id3_meta.cpp
===================================================================
RCS file: /var/cvs/tunepimp/plugins/mp3/id3_meta.cpp,v
retrieving revision 1.2
diff -u -3 -p -r1.2 id3_meta.cpp
--- plugins/mp3/id3_meta.cpp	26 Apr 2004 23:40:50 -0000	1.2
+++ plugins/mp3/id3_meta.cpp	5 Aug 2004 01:55:57 -0000
@@ -3,7 +3,8 @@
    libtunepimp -- The MusicBrainz tagging library.  
                   Let a thousand taggers bloom!
    
-   Copyright (C) Robert Kaye 2003
+   Copyright (C) 2003 Robert Kaye
+   Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
    
    This file is part of libtunepimp.
 
@@ -30,376 +31,305 @@
 #include <musicbrainz/mb_c.h>
 #include "id3_meta.h"
 
-const int iDataFieldLen = 255;
+#include <mpegfile.h>
+#include <id3v2tag.h>
+#include <tbytevectorlist.h>
+#include <tstringlist.h>
+#include <textidentificationframe.h>
+#include <unknownframe.h>
+
+using namespace TagLib;
+
+static const bool useUTF8 = true;
+
+/*!
+ * A subclass of the ID3v2::FrameFactory in TagLib that cleans up the XSOP and
+ * XDOR frames and renames them to the canonical ID3v2.4 frame types TSOP and
+ * TDOR respectively.
+ */
 
-//---------------------------------------------------------------------------
-
-ID3::ID3(bool writeV1) 
+class MBFrameFactory : public ID3v2::FrameFactory
 {
-    this->writeV1 = writeV1;
-}
-
-//---------------------------------------------------------------------------
+    public:
+        static MBFrameFactory *instance()
+        {
+            static MBFrameFactory factory;
+            return &factory;
+        }
 
-string ID3::getText(struct id3_tag *tag, const char *frameName)
-{
-    struct              id3_frame *frame;
-    union               id3_field *field;
-    int                 i;
-    id3_latin1_t       *str;
-    const id3_ucs4_t   *unicode;
-    string              ret;
-
-    frame = id3_tag_findframe(tag, frameName, 0);
-    if (!frame)
-        return ret;
-
-    for(i = 0;; i++)
-    {
-        field = id3_frame_field(frame, i);
-        if (!field)
-            break;
+    protected:
+        MBFrameFactory() : ID3v2::FrameFactory() {}
 
-        if (id3_field_type(field) == ID3_FIELD_TYPE_STRINGLIST)
+        virtual bool updateFrame(ID3v2::Frame::Header *header) const
         {
-            unicode = id3_field_getstrings(field, 0);
-            if (unicode)
-            {
-                str = id3_ucs4_latin1duplicate(unicode);
-                ret = string((char *)str);
-                free(str);
-            }
+            if (header->frameID() == "XSOP")
+                header->setFrameID("TSOP");
+            if (header->frameID() == "XDOR")
+                header->setFrameID("TDOR");
+            return ID3v2::FrameFactory::updateFrame(header);
         }
-    }
-
-    return ret;
-}
+};
 
-//---------------------------------------------------------------------------
+/*!
+ * An implementation of the UFID frame type.  This should move into TagLib
+ * itself in the future.
+ */
 
-string ID3::getUserText(struct id3_tag *tag, const char *userTextName)
+class UniqueFileIDFrame : public ID3v2::Frame
 {
-    struct              id3_frame *frame;
-    union               id3_field *field;
-    int                 i;
-    id3_latin1_t       *str;
-    const id3_ucs4_t   *unicode;
-    string              ret;
-
-    for(i = 0;; i++)
-    {
-        frame = id3_tag_findframe(tag, "TXXX", i);
-        if (!frame)
-            return ret;
-
-        field = id3_frame_field(frame, 1);
-        if (!field)
-            continue; 
-
-        unicode = id3_field_getstring(field);
-        if (unicode)
+    public:
+        UniqueFileIDFrame(const ByteVector &data) :
+            ID3v2::Frame(data)
         {
-            str = id3_ucs4_latin1duplicate(unicode);
-            if (strcmp((const char *)str, userTextName) == 0)
-            {
-                 field = id3_frame_field(frame, 2);
-                 if (!field)
-                     continue; 
-
-                 unicode = id3_field_getstring(field);
-                 if (unicode)
-                 {
-                     str = id3_ucs4_latin1duplicate(unicode);
-                     ret = string((const char *)str);
-                     free(str);
-                     return ret;
-                 }
-            }
-            free(str);
-            continue;
+            setData(data);
         }
-    }
-}
 
-//---------------------------------------------------------------------------
+        UniqueFileIDFrame(const String &owner, const ByteVector &id) :
+            ID3v2::Frame("UFID"),
+            m_owner(owner),
+            m_id(id) {}
+
+        String owner() const { return m_owner; }
+        ByteVector id() const { return m_id; }
+        void setOwner(const String &s) { m_owner = s; }
+        void setID(const ByteVector &v) { m_id = v; }
+        virtual String toString() const { return String::null; }
 
-string ID3::getUniqueFileId(struct id3_tag *tag, const char *ufidName)
-{
-    struct              id3_frame *frame;
-    union               id3_field *field;
-    int                 i;
-    const id3_latin1_t *text;
-    string              ret;
-
-    for(i = 0;; i++)
-    {
-        frame = id3_tag_findframe(tag, "UFID", i);
-        if (!frame)
-            return ret;
-
-        field = id3_frame_field(frame, 0);
-        if (!field)
-            continue;
+    protected:
+        virtual void parseFields(const ByteVector &data)
+        {
+            ByteVectorList fields = ByteVectorList::split(data, char(0));
+            if(fields.size() != 2)
+                return;
 
-        text = id3_field_getlatin1(field);
-        if (text)
+            m_owner = fields.front();
+            m_id = fields.back();
+        }
+        virtual ByteVector renderFields() const
         {
-            if (strcmp((const char *)text, ufidName) == 0)
-            {
-                field = id3_frame_field(frame, 1);
-                if (field)
-                {
-                    char *temp, *ptr;
-                    id3_length_t len;
-
-                    ptr = (char *)id3_field_getbinarydata(field, &len);
-                    temp = new char[len + 1];
-                    memcpy(temp, ptr, len);
-                    temp[len] = 0;
+            ByteVector data;
+            data.append(m_owner.data(String::Latin1));
+            data.append(char(0));
+            data.append(m_id);
+            return data;
+        }
 
-                    ret = temp;
+    private:
+        String m_owner;
+        ByteVector m_id;
+};
+
+/*!
+ * This is a workaround for a bug in TagLib 1.2 and below not recognizing
+ * TXXX frames as text frames and to map our UFID class above into the
+ * set of recognized frames.
+ */
 
-                    return ret;
-                }
-            }
-            continue;
+static void fixFrames(ID3v2::Tag *tag)
+{
+    ID3v2::FrameList frames = tag->frameList("TXXX");
+    for (ID3v2::FrameList::ConstIterator it = frames.begin(); it != frames.end(); ++it)
+    {
+        if (dynamic_cast<ID3v2::UnknownFrame *>(*it))
+        {
+            ID3v2::TextIdentificationFrame *f =
+                new ID3v2::TextIdentificationFrame((*it)->render());
+            tag->removeFrame(*it);
+            tag->addFrame(f);
         }
     }
 
-    return ret;
+    frames = tag->frameList("UFID");
+
+    for (ID3v2::FrameList::ConstIterator it = frames.begin(); it != frames.end(); ++it)
+    {
+        if (dynamic_cast<ID3v2::UnknownFrame *>(*it))
+        {
+            UniqueFileIDFrame *f = new UniqueFileIDFrame((*it)->render());
+            tag->removeFrame(*it);
+            tag->addFrame(f);
+        }
+    }
 }
 
 //---------------------------------------------------------------------------
 
-bool ID3::setText(struct id3_tag *tag, const char *frameName, const string &text)
+static void setText(ID3v2::Tag *tag, const string &frameID, const string &text)
 {
-    struct id3_frame *frame;
-    union  id3_field *field;
-    id3_ucs4_t       *unicode;
+    String::Type encoding = useUTF8 ? String::UTF8 : String::Latin1;
 
-    frame = id3_tag_findframe(tag, frameName, 0);
-    if (!frame)
+    if (!tag->frameList(frameID.c_str()).isEmpty())
     {
-        frame = id3_frame_new(frameName);
-        id3_tag_attachframe(tag, frame);
+        tag->frameList(frameID.c_str()).front()->setText(String(text, encoding));
     }
-    if (frame)
+    else
     {
-         field = id3_frame_field(frame, 1);
-         if (field)
-         {
-             unicode = id3_latin1_ucs4duplicate((id3_latin1_t *)text.c_str());
-             id3_field_setstrings(field, 1, &unicode);
-             free(unicode);
-
-             return true;
-         }
-    }
-
-    frame = id3_frame_new(frameName);
-
-    field = id3_frame_field(frame, 1);
-    if (!field)
-        return false;
-
-    unicode = id3_latin1_ucs4duplicate((id3_latin1_t *)text.c_str());
-    id3_field_setstrings(field, 1, &unicode);
-    free((void *)unicode);
-
-    id3_tag_attachframe(tag, frame);
-
-    return true;
+        String::Type defaultEncoding = MBFrameFactory::instance()->defaultTextEncoding();
+        ID3v2::TextIdentificationFrame *f =
+            new ID3v2::TextIdentificationFrame(frameID.c_str(), defaultEncoding);
+        tag->addFrame(f);
+        f->setText(String(text, encoding));
+    }    
 }
 
 //---------------------------------------------------------------------------
 
-bool ID3::setUserText(struct id3_tag *tag, const char *userTextName, const string &text)
+static ID3v2::TextIdentificationFrame *findUserTextFrame(ID3v2::Tag *tag,
+                                                         const string &description)
 {
-    struct              id3_frame *frame;
-    union               id3_field *field;
-    int                 i;
-    id3_latin1_t       *str;
-    const id3_ucs4_t   *unicode;
-
-    for(i = 0;; i++)
-    {
-        frame = id3_tag_findframe(tag, "TXXX", i);
-        if (!frame)
-            break;
-
-        field = id3_frame_field(frame, 1);
-        if (!field)
-            continue; 
-
-        unicode = id3_field_getstring(field);
-        if (unicode)
+    const ID3v2::FrameList &frames = tag->frameList("TXXX");
+    for (ID3v2::FrameList::ConstIterator it = frames.begin(); it != frames.end(); ++it)
+    {
+        ID3v2::TextIdentificationFrame *frame =
+            dynamic_cast<ID3v2::TextIdentificationFrame *>(*it);
+        if (frame &&
+            frame->fieldList().size() == 2 &&
+            frame->fieldList().front() == description)
         {
-            str = id3_ucs4_latin1duplicate(unicode);
-            if (strcmp((const char *)str, userTextName) == 0)
-            {
-                 free(str);
-
-                 field = id3_frame_field(frame, 2);
-                 if (!field)
-                     continue; 
-
-                 unicode = id3_latin1_ucs4duplicate((id3_latin1_t *)text.c_str());
-                 id3_field_setstring(field, unicode);
-                 free((void *)unicode);
-                 return true;
-            }
-            free(str);
-            continue;
+            return frame;
         }
     }
+    return 0;
+}
 
-    frame = id3_frame_new("TXXX");
-
-    field = id3_frame_field(frame, 0);
-    if (!field)
-        return false;
-    id3_field_setint(field, 0);
-
-    field = id3_frame_field(frame, 1);
-    if (!field)
-        return false;
-
-    unicode = id3_latin1_ucs4duplicate((id3_latin1_t *)userTextName);
-    id3_field_setstring(field, unicode);
-    free((void *)unicode);
+//---------------------------------------------------------------------------
 
-    field = id3_frame_field(frame, 2);
-    if (!field)
-        return false;
+static string getUserText(ID3v2::Tag *tag, const string &description)
+{
+    ID3v2::TextIdentificationFrame *f = findUserTextFrame(tag, description);
+    return f ? f->fieldList().back().to8Bit(useUTF8) : string();
+}
 
-    unicode = id3_latin1_ucs4duplicate((id3_latin1_t *)text.c_str());
-    id3_field_setstring(field, unicode);
-    free((void *)unicode);
-    
-    id3_tag_attachframe(tag, frame);
+//---------------------------------------------------------------------------
 
-    return true;
+static void setUserText(ID3v2::Tag *tag, const string &description, const string &text)
+{
+    StringList l;
+    l.append(description);
+    l.append(text);
+
+    ID3v2::TextIdentificationFrame *f = findUserTextFrame(tag, description);
+    if (!f)
+    {
+        String::Type encoding = MBFrameFactory::instance()->defaultTextEncoding();
+        f = new ID3v2::TextIdentificationFrame("TXXX", encoding);
+        tag->addFrame(f);
+    }
+    f->setText(l);
 }
 
 //---------------------------------------------------------------------------
 
-bool ID3::setUniqueFileId(struct id3_tag *tag, const char *ufidName, const string &id)
+static UniqueFileIDFrame *findUniqueFileIDFrame(ID3v2::Tag *tag,
+                                                const string &owner)
 {
-    struct              id3_frame *frame;
-    union               id3_field *field;
-    int                 i;
-    const id3_latin1_t *text;
-    string              ret;
-
-    for(i = 0;; i++)
-    {
-        frame = id3_tag_findframe(tag, "UFID", i);
-        if (!frame)
-            break;
-
-        field = id3_frame_field(frame, 0);
-        if (!field)
-            continue;
-
-        text = id3_field_getlatin1(field);
-        if (text)
-        {
-            if (strcmp((const char *)text, ufidName) == 0)
-            {
-                field = id3_frame_field(frame, 1);
-                if (field)
-                {
-                    id3_field_setbinarydata(field, (const id3_byte_t *)id.c_str(), 
-                                            id.size());
-                    return true;
-                }
-            }
-            continue;
-        }
+    const ID3v2::FrameList &frames = tag->frameList("UFID");
+    for (ID3v2::FrameList::ConstIterator it = frames.begin(); it != frames.end(); ++it)
+    {
+        UniqueFileIDFrame *f = dynamic_cast<UniqueFileIDFrame *>(*it);
+        if (f && f->owner() == owner)
+            return f;
     }
+    return 0;
+}
 
-    frame = id3_frame_new("UFID");
+//---------------------------------------------------------------------------
 
-    field = id3_frame_field(frame, 0);
-    if (!field)
-        return false;
+static string getUniqueFileId(ID3v2::Tag *tag, const string &owner)
+{
+    UniqueFileIDFrame *f = findUniqueFileIDFrame(tag, owner);
+    return f ? f->id().data() : string();
+}
 
-    id3_field_setlatin1(field, (id3_latin1_t*)ufidName);
+//---------------------------------------------------------------------------
 
-    field = id3_frame_field(frame, 1);
-    if (!field)
-        return false;
+static void setUniqueFileId(ID3v2::Tag *tag, const string &owner, const string &id)
+{
+    UniqueFileIDFrame *f = findUniqueFileIDFrame(tag, owner);
+    if (!f)
+    {
+        f = new UniqueFileIDFrame(owner.c_str(), id.c_str());
+        tag->addFrame(f);
+    }
+    f->setID(id.c_str());
+}
 
-    id3_field_setbinarydata(field, (const id3_byte_t*)id.c_str(), id.size());
-    id3_tag_attachframe(tag, frame);
+//---------------------------------------------------------------------------
 
-    return true;
+ID3::ID3(bool writeV1) 
+{
+    this->writeV1 = writeV1;
 }
 
-// Check ID3v1 support
+//---------------------------------------------------------------------------
+
 bool ID3::read(const string &fileName, Metadata &data)
 {
-    struct        id3_file *file;
-    struct        id3_tag *tag;
-    string        temp;
+    MPEG::File file(fileName.c_str(), MBFrameFactory::instance());
 
-    file = id3_file_open(fileName.c_str(), ID3_FILE_MODE_READONLY);
-    if (file == NULL)
+    if (!file.isOpen())
+    {
+        errString = "File could not be opened";
         return false;
+    }
 
-    tag = id3_file_tag(file);
-    if (tag == NULL)
+    if (!file.isValid())
     {
-        id3_file_close(file);
+        errString = "File is not a valid MP3 file or there was an error while reading";
         return false;
     }
 
-    data.artist = getText(tag, ID3_FRAME_ARTIST);
-    data.album = getText(tag, ID3_FRAME_ALBUM);
-    data.track = getText(tag, ID3_FRAME_TITLE);
-    data.trackNum = atoi(getText(tag, ID3_FRAME_TRACK).c_str());
-    data.sortName = getText(tag, "XSOP");
-    if (data.sortName.empty())
-       data.sortName = getUserText(tag, "MusicBrainz Artist Sortname");
-
-    data.fileTrm = getUserText(tag, "MusicBrainz TRM Id");
-    data.artistId = getUserText(tag, "MusicBrainz Artist Id");
-    data.albumId = getUserText(tag, "MusicBrainz Album Id");
-    data.albumArtistId = getUserText(tag, "MusicBrainz Album Artist Id");
-    data.trackId = getUniqueFileId(tag, "http://musicbrainz.org");
-    temp = getUserText(tag, "MusicBrainz Album Type");
-    if (temp.length() > 0)
-       data.albumType = convertToAlbumType(temp.c_str());
-    temp = getUserText(tag, "MusicBrainz Album Status");
-    if (temp.length() > 0)
-       data.albumStatus = convertToAlbumStatus(temp.c_str());
-    data.variousArtist = strcmp(data.albumArtistId.c_str(), MBI_VARIOUS_ARTIST_ID) == 0;
-    data.fileFormat = "mp3";
+    data.artist      = file.tag()->artist().to8Bit(useUTF8);
+    data.album       = file.tag()->album().to8Bit(useUTF8);
+    data.track       = file.tag()->title().to8Bit(useUTF8);
+    data.trackNum    = file.tag()->track();
+    data.releaseYear = file.tag()->year();
+
+    if (file.ID3v2Tag())
+    {
+        ID3v2::Tag *tag = file.ID3v2Tag();
 
-    temp = getText(tag, "TORY");
-    if (temp.length())
-        data.releaseYear = atoi(temp.c_str());
+        fixFrames(tag);
 
-    temp = getText(tag, "TYER");
-    if (temp.length() && (data.releaseYear < 1800 || data.releaseYear > 3000))
-        data.releaseYear = atoi(temp.c_str());
+        if (!tag->frameList("TSOP").isEmpty())
+            data.sortName = tag->frameList("TSOP").front()->toString().to8Bit(useUTF8);
 
-    temp = getText(tag, "XDOR");
-    if (temp.length())
-    {
-        int year, month, day;
+        if (data.sortName.empty())
+            data.sortName  = getUserText(tag, "MusicBrainz Artist Sortname");
+
+        data.fileTrm       = getUserText(tag, "MusicBrainz TRM Id");
+        data.artistId      = getUserText(tag, "MusicBrainz Artist Id");
+        data.albumId       = getUserText(tag, "MusicBrainz Album Id");
+        data.albumArtistId = getUserText(tag, "MusicBrainz Album Artist Id");
+
+        data.trackId = getUniqueFileId(tag, "http://musicbrainz.org");
 
-        year = month = day = 0;
-        if (sscanf(temp.c_str(), "%04d-%02d-%02d", &year, &month, &day) > 0)
+        string albumType = getUserText(tag, "MusicBrainz Album Type");
+        if (!albumType.empty())
+            data.albumType = convertToAlbumType(albumType.c_str());
+
+        string albumStatus = getUserText(tag, "MusicBrainz Album Status");
+        if (!albumStatus.empty())
+            data.albumStatus = convertToAlbumStatus(albumStatus.c_str());
+
+        if (!tag->frameList("TDOR").isEmpty())
         {
-            data.releaseYear = year;
-            data.releaseMonth = month;
-            data.releaseDay = day;
+            StringList dateFields =
+                StringList::split(tag->frameList("TDOR").front()->toString(), "-");
+
+            if (dateFields.size() == 3)
+            {
+                data.releaseYear  = dateFields[0].toInt();
+                data.releaseMonth = dateFields[1].toInt();
+                data.releaseDay   = dateFields[2].toInt();
+            }
         }
+
+        data.releaseCountry = getUserText(tag, "MusicBrainz Album Release Country");
     }
-    data.releaseCountry = getUserText(tag, "MusicBrainz Album Release Country");
 
-    id3_file_close(file);
+    data.variousArtist = strcmp(data.albumArtistId.c_str(), MBI_VARIOUS_ARTIST_ID) == 0;
+    data.fileFormat = "mp3";
 
     return true;
 }
@@ -410,82 +340,88 @@ bool ID3::write(const string  &fileName,
                 const Metadata    &data,
                 bool               clear)
 {
-    struct        id3_file *file;
-    struct        id3_tag *tag;
-    char          temp[20];
-    int           ret;
-    string        temp2;
+    MPEG::File file(fileName.c_str());
 
-    file = id3_file_open(fileName.c_str(), ID3_FILE_MODE_READWRITE);
-    if (file == NULL)
+    if (!file.isOpen())
+    {
+        errString = "File could not be opened";
         return false;
+    }
 
-    tag = id3_file_tag(file);
-    if (tag == NULL)
+    if (!file.isValid())
     {
-        id3_file_close(file);
+        errString = "File is not a valid MP3 file or there was an error while reading";
         return false;
     }
 
-    if (clear)
-        id3_tag_clearframes(tag);
+    if (file.readOnly())
+    {
+        errString = "Cannot open file for writing";
+        return false;        
+    }
 
-    setText(tag, ID3_FRAME_ARTIST, data.artist);
-    setText(tag, ID3_FRAME_ALBUM, data.album);
-    setText(tag, ID3_FRAME_TITLE, data.track);
-    sprintf(temp, "%d", data.trackNum);
-    setText(tag, ID3_FRAME_TRACK, string(temp));
-    if (!data.sortName.empty())
-        setText(tag, "XSOP", data.sortName);
+    ID3v2::Tag *tag = file.ID3v2Tag(true);
+    fixFrames(tag);
+
+    while (clear && !tag->frameList().isEmpty())
+        tag->removeFrame(tag->frameList().front());
+
+    String::Type encoding = useUTF8 ? String::UTF8 : String::Latin1;
+
+    file.tag()->setArtist(String(data.artist, encoding));
+    file.tag()->setAlbum(String(data.album, encoding));
+    file.tag()->setTitle(String(data.track, encoding));
+    file.tag()->setTrack(data.trackNum);
+
+    setText(tag, "TSOP", data.sortName);
 
     setUserText(tag, "MusicBrainz TRM Id", data.fileTrm);
     setUserText(tag, "MusicBrainz Artist Id", data.artistId);
     setUserText(tag, "MusicBrainz Album Id", data.albumId);
+
     if (data.albumType != eAlbumType_Error)
     {
-        convertFromAlbumType(data.albumType, temp2);
-        setUserText(tag, "MusicBrainz Album Type", temp2);
+        string s;
+        convertFromAlbumType(data.albumType, s);
+        setUserText(tag, "MusicBrainz Album Type", s);
     }
+
     if (data.albumStatus != eAlbumStatus_Error)
     {
-        convertFromAlbumStatus(data.albumStatus, temp2);
-        setUserText(tag, "MusicBrainz Album Status", temp2);
+        string s;
+        convertFromAlbumStatus(data.albumStatus, s);
+        setUserText(tag, "MusicBrainz Album Status", s);
     }
+
     if (data.variousArtist)
         setUserText(tag, "MusicBrainz Album Artist Id", MBI_VARIOUS_ARTIST_ID);
     else
-        setUserText(tag, "MusicBrainz Album Artist Id", data.albumArtistId.c_str());
+        setUserText(tag, "MusicBrainz Album Artist Id", data.albumArtistId);
+
     setUniqueFileId(tag, "http://musicbrainz.org", data.trackId);
 
     if (data.releaseYear > 0)
     {
-        char temp[16];
-    
-        sprintf(temp, "%02d", data.releaseYear);
+        char s[16];
+
+        sprintf(s, "%02d", data.releaseYear);
         if (data.releaseMonth > 0)
         {
-            sprintf(temp + strlen(temp), "-%02d", data.releaseMonth);
+            sprintf(s + strlen(s), "-%02d", data.releaseMonth);
             if (data.releaseDay > 0)
-                sprintf(temp + strlen(temp), "-%02d", data.releaseDay);
+                sprintf(s + strlen(s), "-%02d", data.releaseDay);
         }
-        setText(tag, "XDOR", temp);
-    }
-    if (data.releaseYear > 0)
-    {
-        char temp[16];
-    
-        sprintf(temp, "%d", data.releaseYear);
-        setText(tag, "TORY", temp);
+
+        setText(tag, "TDOR", s);
     }
+
     if (data.releaseCountry.length() > 0)
         setUserText(tag, "MusicBrainz Album Release Country", data.releaseCountry);
 
-    id3_tag_options(tag, ID3_TAG_OPTION_COMPRESSION, 0);
-    id3_tag_options(tag, ID3_TAG_OPTION_CRC, 0);
-    id3_tag_options(tag, ID3_TAG_OPTION_UNSYNCHRONISATION, 0);
-    id3_tag_options(tag, ID3_TAG_OPTION_ID3V1, writeV1 ? ID3_TAG_OPTION_ID3V1 : 0);
-    ret = id3_file_update(file);
-    id3_file_close(file);
+    bool saved = file.save(writeV1 ? MPEG::File::AllTags : MPEG::File::ID3v2);
+
+    if(!saved)
+        errString = "Could not save file";
 
-    return ret == 0;
+    return saved;
 }
Index: plugins/mp3/id3_meta.h
===================================================================
RCS file: /var/cvs/tunepimp/plugins/mp3/id3_meta.h,v
retrieving revision 1.1
diff -u -3 -p -r1.1 id3_meta.h
--- plugins/mp3/id3_meta.h	23 Apr 2004 00:12:21 -0000	1.1
+++ plugins/mp3/id3_meta.h	5 Aug 2004 01:55:57 -0000
@@ -49,25 +49,9 @@ class ID3
        void getError(string &error) { error = errString; };
 
     protected:
-
        string errString;
 
     private:
-
-       string     getText        (struct id3_tag *tag, const char *frameName);
-       string     getUserText    (struct id3_tag *tag, const char *userTextName);
-       string     getUniqueFileId(struct id3_tag *tag, const char *ufidName);
-
-       bool       setUniqueFileId(struct id3_tag *tag, 
-                                  const char *ufidName, 
-                                  const string &id);
-       bool       setUserText    (struct id3_tag *tag, 
-                                  const char *userTextName, 
-                                  const string &text);
-       bool       setText(struct id3_tag *tag, 
-                                  const char *frameName,
-                                  const string &text);
-
        bool       writeV1;
 };
 

