Logo Search packages:      
Sourcecode: zinf version File versions  Download package

id3lib.cpp

/*____________________________________________________________________________
      
      Zinf - Zinf Is Not FreeA*p (The Free MP3 Player)

      Portions Copyright (C) 1999 EMusic.com

      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      
      $Id: id3lib.cpp,v 1.11 2004/02/14 01:51:03 kgk Exp $
____________________________________________________________________________*/

#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>

#ifdef __QNX__
#include <strings.h>
#endif
using namespace std;
#include "errors.h"
#include "utility.h"
#include "debug.h"

#include "id3lib.h"

#include <id3/tag.h>

#ifdef HAVE_GLIB
#include <glib.h>
#endif

#define DB printf("%s:%d\n", __FILE__, __LINE__);

const int iDataFieldLen = 1024;
const int genreOther = 12;
#define genreMax (int)(sizeof(genreList)/sizeof(char*))

const char *genreList[] = 
{
     "Blues",
     "Classic Rock",
     "Country",
     "Dance",
     "Disco",
     "Funk",
     "Grunge",
     "Hip-Hop",
     "Jazz",
     "Metal",
     "New Age",
     "Oldies",
     "Other",
     "Pop",
     "R&B",
     "Rap",
     "Reggae",
     "Rock",
     "Techno",
     "Industrial",
     "Alternative",
     "Ska",
     "Death Metal",
     "Pranks",
     "Soundtrack",
     "Euro-Techno",
     "Ambient",
     "Trip-Hop",
     "Vocal",
     "Jazz+Funk",
     "Fusion",
     "Trance",
     "Classical",
     "Instrumental",
     "Acid",
     "House",
     "Game",
     "Sound Clip",
     "Gospel",
     "Noise",
     "AlternRock",
     "Bass",
     "Soul",
     "Punk",
     "Space",
     "Meditative",
     "Instrumental Pop",
     "Instrumental Rock",
     "Ethnic",
     "Gothic",
     "Darkwave",
     "Techno-Industrial",
     "Electronic",
     "Pop-Folk",
     "Eurodance",
     "Dream",
     "Southern Rock",
     "Comedy",
     "Cult",
     "Gangsta",
     "Top 40",
     "Christian Rap",
     "Pop/Funk",
     "Jungle",
     "Native American",
     "Cabaret",
     "New Wave",
     "Psychadelic",
     "Rave",
     "Showtunes",
     "Trailer",
     "Lo-Fi",
     "Tribal",
     "Acid Punk",
     "Acid Jazz",
     "Polka",
     "Retro",
     "Musical",
     "Rock & Roll",
     "Hard Rock",
     "Folk",
     "Folk-Rock",
     "National Folk",
     "Swing",
     "Fast Fusion",
     "Bebob",
     "Latin",
     "Revival",
     "Celtic",
     "Bluegrass",
     "Avantgarde",
     "Gothic Rock",
     "Progressive Rock",
     "Psychedelic Rock",
     "Symphonic Rock",
     "Slow Rock",
     "Big Band",
     "Chorus",
     "Easy Listening",
     "Acoustic",
     "Humour",
     "Speech",
     "Chanson",
     "Opera",
     "Chamber Music",
     "Sonata",
     "Symphony",
     "Booty Bass",
     "Primus",
     "Porn Groove",
     "Satire",
     "Slow Jam",
     "Club",
     "Tango",
     "Samba",
     "Folklore",
     "Ballad",
     "Power Ballad",
     "Rhythmic Soul",
     "Freestyle",
     "Duet",
     "Punk Rock",
     "Drum Solo",
     "Acapella",
     "Euro-House",
     "Dance Hall",
};


static char* id3frame_names[] = {

  /* ???? */  ""  ,       /**< No known frame */
  /* AENC */  "",        /**< Audio encryption */
  /* APIC */  "",            /**< Attached picture */
  /* ASPI */  "",     /**< Audio seek point index */
  /* COMM */  "comment",            /**< Comments */
  /* COMR */  "COMMERCIAL",         /**< Commercial frame */
  /* ENCR */  "CRYPTOREG",          /**< Encryption method registration */
  /* EQU2 */  "EQUALIZATION2",      /**< Equalisation (2) */
  /* EQUA */  "EQUALIZATION",       /**< Equalization */
  /* ETCO */  "EVENTTIMING",        /**< Event timing codes */
  /* GEOB */  "GENERALOBJECT",      /**< General encapsulated object */
  /* GRID */  "GROUPINGREG",        /**< Group identification registration */
  /* IPLS */  "INVOLVEDPEOPLE",     /**< Involved people list */
  /* LINK */  "LINKEDINFO",         /**< Linked information */
  /* MCDI */  "CDID",               /**< Music CD identifier */
  /* MLLT */  "MPEGLOOKUP",         /**< MPEG location lookup table */
  /* OWNE */  "OWNERSHIP",          /**< Ownership frame */
  /* PRIV */  "PRIVATE",            /**< Private frame */
  /* PCNT */  "PLAYCOUNTER",        /**< Play counter */
  /* POPM */  "POPULARIMETER",      /**< Popularimeter */
  /* POSS */  "POSITIONSYNC",       /**< Position synchronisation frame */
  /* RBUF */  "BUFFERSIZE",         /**< Recommended buffer size */
  /* RVA2 */  "VOLUMEADJ2",         /**< Relative volume adjustment (2) */
  /* RVAD */  "VOLUMEADJ",          /**< Relative volume adjustment */
  /* RVRB */  "REVERB",             /**< Reverb */
  /* SEEK */  "SEEKFRAME",          /**< Seek frame */
  /* SIGN */  "SIGNATURE",          /**< Signature frame */
  /* SYLT */  "SYNCEDLYRICS",       /**< Synchronized lyric/text */
  /* SYTC */  "SYNCEDTEMPO",        /**< Synchronized tempo codes */
  /* TALB */  "album",              /**< Album/Movie/Show title */
  /* TBPM */  "BPM",                /**< BPM (beats per minute) */
  /* TCOM */  "composer",           /**< Composer */
  /* TCON */  "CONTENTTYPE",        /**< Content type */
  /* TCOP */  "copyright",          /**< Copyright message */
  /* TDAT */  "DATE",               /**< Date */
  /* TDEN */  "ENCODINGTIME",       /**< Encoding time */
  /* TDLY */  "PLAYLISTDELAY",      /**< Playlist delay */
  /* TDOR */  "ORIGRELEASETIME",    /**< Original release time */
  /* TDRC */  "RECORDINGTIME",      /**< Recording time */
  /* TDRL */  "RELEASETIME",        /**< Release time */
  /* TDTG */  "TAGGINGTIME",        /**< Tagging time */
  /* TIPL */  "INVOLVEDPEOPLE2",    /**< Involved people list */
  /* TENC */  "ENCODEDBY",          /**< Encoded by */
  /* TEXT */  "lyricist",           /**< Lyricist/Text writer */
  /* TFLT */  "FILETYPE",           /**< File type */
  /* TIME */  "TIME",               /**< Time */
  /* TIT1 */  "CONTENTGROUP",       /**< Content group description */
  /* TIT2 */  "title",              /**< Title/songname/content description */
  /* TIT3 */  "SUBTITLE",           /**< Subtitle/Description refinement */
  /* TKEY */  "INITIALKEY",         /**< Initial key */
  /* TLAN */  "LANGUAGE",           /**< Language(s) */
  /* TLEN */  "SONGLEN",            /**< Length */
  /* TMCL */  "MUSICIANCREDITLIST", /**< Musician credits list */
  /* TMED */  "MEDIATYPE",          /**< Media type */
  /* TMOO */  "MOOD",               /**< Mood */
  /* TOAL */  "ORIGALBUM",          /**< Original album/movie/show title */
  /* TOFN */  "ORIGFILENAME",       /**< Original filename */
  /* TOLY */  "ORIGLYRICIST",       /**< Original lyricist(s)/text writer(s) */
  /* TOPE */  "ORIGARTIST",         /**< Original artist(s)/performer(s) */
  /* TORY */  "ORIGYEAR",           /**< Original release year */
  /* TOWN */  "FILEOWNER",          /**< File owner/licensee */
  /* TPE1 */  "artist",         /**< Lead performer(s)/Soloist(s) */
  /* TPE2 */  "ensemble",               /**< Band/orchestra/accompaniment */
  /* TPE3 */  "conductor",          /**< Conductor/performer refinement */
  /* TPE4 */  "MIXARTIST",          /**< Interpreted, remixed, or otherwise modified by */
  /* TPOS */  "partnumber",          /**< Part of a set */
  /* TPRO */  "PRODUCEDNOTICE",     /**< Produced notice */
  /* TPUB */  "publisher",          /**< Publisher */
  /* TRCK */  "tracknumber",           /**< Track number/Position in set */
  /* TRDA */  "date",     /**< Recording dates */
  /* TRSN */  "NETRADIOSTATION",    /**< Internet radio station name */
  /* TRSO */  "NETRADIOOWNER",      /**< Internet radio station owner */
  /* TSIZ */  "SIZE",               /**< Size */
  /* TSOA */  "ALBUMSORTORDER",     /**< Album sort order */
  /* TSOP */  "PERFORMERSORTORDER", /**< Performer sort order */
  /* TSOT */  "TITLESORTORDER",     /**< Title sort order */
  /* TSRC */  "isrc",               /**< ISRC (international standard recording code) */
  /* TSSE */  "encoding",    /**< Software/Hardware and settings used for encoding */
  /* TSST */  "SETSUBTITLE",        /**< Set subtitle */
  /* TXXX */  "USERTEXT",           /**< User defined text information */
  /* TYER */  "YEAR",               /**< Year */
  /* UFID */  "UNIQUEFILEID",       /**< Unique file identifier */
  /* USER */  "TERMSOFUSE",         /**< Terms of use */
  /* USLT */  "UNSYNCEDLYRICS",     /**< Unsynchronized lyric/text transcription */
  /* WCOM */  "WWWCOMMERCIALINFO",  /**< Commercial information */
  /* WCOP */  "WWWCOPYRIGHT",       /**< Copyright/Legal infromation */
  /* WOAF */  "WWWAUDIOFILE",       /**< Official audio file webpage */
  /* WOAR */  "WWWARTIST",          /**< Official artist/performer webpage */
  /* WOAS */  "WWWAUDIOSOURCE",     /**< Official audio source webpage */
  /* WORS */  "WWWRADIOPAGE",       /**< Official internet radio station homepage */
  /* WPAY */  "WWWPAYMENT",         /**< Payment */
  /* WPUB */  "WWWPUBLISHER",       /**< Official publisher webpage */
  /* WXXX */  "WWWUSER",            /**< User defined URL link */
  /*      */  "METACRYPTO",         /**< Encrypted meta frame (id3v2.2.x) */
  /*      */  "METACOMPRESSION",    /**< Compressed meta frame (id3v2.2.1) */
};

string charset="ISO-8859-1";



#ifndef COMPILING_SIGAPP
extern "C"
{
   MetaDataFormat *Initialize(FAContext* context)
   {
      return new ID3lib(context);
   }
}
#endif

ID3lib::ID3lib(FAContext* context)
  : MetaDataFormat(context)
{
}

ID3lib::~ID3lib()
{
}


static
bool getTag(ID3_Tag&tag, ID3_FrameID frameid, string &result)
{
    static char buffer[1024];
#ifdef HAVE_GLIB
    gchar *utfbuffer;
#endif

    ID3_Frame *frame;
    ID3_Field *field;

    frame = tag.Find(frameid);
    if (frame) {
      field = frame->GetField (ID3FN_TEXT);
      if (field) 
        if (field->Get (buffer, sizeof buffer) > 0) {
#ifdef HAVE_GLIB
        if (g_utf8_validate (buffer, -1 , NULL)){
          result = buffer;
          return true;
        }
        else {
          utfbuffer=g_convert(buffer, sizeof buffer, "UTF-8", charset.c_str(), NULL, NULL, NULL);
          result=utfbuffer;
          g_free(utfbuffer);
          return true;
        }
#else
         result=buffer;
         return true;
#endif
        }
    }
    return false;
}

static
bool setTag(ID3_Tag&tag, ID3_FrameID frameid, const string &result)
{
  
    ID3_Frame *frame;
    ID3_Field *field;

    frame = tag.Find(frameid);
    if (!frame) { 
      frame = new ID3_Frame(frameid); 
      tag.AttachFrame (frame);
    }
    field = frame->GetField (ID3FN_TEXT);
    field->Set (result.c_str());

    return true;
}

bool ID3lib::ReadMetaData(const char* url, MetaData* metadata)
{
    assert(url);
    assert(metadata);

    char *ptr = strrchr(url, '.');
    if (ptr == NULL)
        return false;

    if (strcasecmp(ptr, ".mp3")) 
        return false;

    string path;
    URLToFilePath(url, path);

    ID3_Tag tag;
    string val;
    tag.Link( path.c_str());

    m_context->prefs->GetPrefString(kDefaultID3CharsetPref, &charset);
    if (getTag(tag, ID3FID_TITLE,  val)) 
      metadata->SetTitle(val);
    if (getTag(tag, ID3FID_ALBUM,  val)) 
      metadata->SetAlbum(val);
    if (getTag(tag, ID3FID_LEADARTIST,  val)) 
      metadata->SetArtist(val);
    else if (getTag(tag, ID3FID_BAND,  val)) 
      metadata->SetArtist(val);
    if (getTag(tag, ID3FID_COMMENT,  val)) 
      metadata->SetComment(val);
    if (getTag(tag, ID3FID_SONGLEN,  val)) 
      metadata->SetTime(atoi(val.c_str()) / 1000);
    if (getTag(tag, ID3FID_YEAR,  val)) 
      metadata->SetYear(atoi(val.c_str()));
    if (getTag(tag, ID3FID_SIZE,  val)) 
      metadata->SetSize(atoi(val.c_str()));
    if (getTag(tag, ID3FID_TRACKNUM,  val)) 
      metadata->SetTrack(atoi(val.c_str()));
    if (getTag(tag, ID3FID_CONTENTTYPE,  val)) {
        char genre[255];
        int  genreId, ret;
        ret = sscanf(val.c_str(), "(%d)%[^\n]", &genreId, genre);
        if (ret > 0) {
            if (ret == 2)
                metadata->SetGenre(genre);
            else if (genreId != genreOther) {
                LookupGenre(genreId, genre);
                metadata->SetGenre(genre);
            }
        }
        else {
            metadata->SetGenre(val);
        }
    }

    return true;
}

bool ID3lib::WriteMetaData(const char* url, const MetaData& metadata)
{
    char      dummy[20];
    bool      bWriteID3v1, bWriteID3v2;
    luint     whichTags;
    char     *ptr;

    ptr = strrchr(url, '.');
    if (ptr == NULL)
        return false;

    if (strcasecmp(ptr, ".mp3"))
        return false;  

    m_context->prefs->GetPrefBoolean(kWriteID3v1Pref, &bWriteID3v1);
    m_context->prefs->GetPrefBoolean(kWriteID3v2Pref, &bWriteID3v2);

    whichTags = (bWriteID3v1) ? ID3TT_ID3V1 : 0;
    whichTags |= (bWriteID3v2) ? ID3TT_ID3V2 : 0;

    if (!whichTags)
        return true;

    assert(url);

    string path;
    URLToFilePath(url, path);

    ID3_Tag tag;

    tag.Link (path.c_str(), whichTags);

    setTag(tag, ID3FID_TITLE, metadata.Title());
    setTag(tag, ID3FID_ALBUM, metadata.Album());
    setTag(tag, ID3FID_LEADARTIST, metadata.Artist());
    setTag(tag, ID3FID_COMMENT, metadata.Comment());

    sprintf(dummy, "%d", metadata.Time() * 1000);
    setTag(tag, ID3FID_SONGLEN, dummy);

    sprintf(dummy, "%d", metadata.Year());
    setTag(tag, ID3FID_YEAR, dummy);

    sprintf(dummy, "%d", metadata.Size());
    setTag(tag, ID3FID_SIZE, dummy);

    sprintf(dummy, "%d", metadata.Track());
    setTag(tag, ID3FID_TRACKNUM, dummy);

    sprintf(dummy, "(%d)%s", genreOther, metadata.Genre().c_str());
    setTag(tag, ID3FID_CONTENTTYPE, dummy);

    tag.Update();
    return true;
}


void ID3lib::LookupGenre(int genreId, char* genre)
{
    if (0 <= genreId && genreId < genreMax) {
        strcpy(genre, genreList[genreId]);
        return;
    }
    genre[0] = 0;
}


bool ID3lib::readMetadata(const std::string&url, map_type& pairs)
{
    char *ptr = strrchr(url.c_str(), '.');
    if (ptr == NULL)
        return false;

    if (strcasecmp(ptr, ".mp3")) 
        return false;

    string path;
    URLToFilePath(url, path);

    //cout << "mp3 " << path << endl;

    ID3_Tag tag;
    string val;
    tag.Link( path.c_str());

    ID3_Tag::Iterator *ti = tag.CreateIterator();

    ID3_Frame *frame = 0;
    ID3_Field *field;
    static char buffer[1024];
    while ((frame = ti->GetNext()) != 0){
        int32_t index = (int32_t)frame->GetID();

      if (!islower(id3frame_names[index][0])) continue;
        string id3tag = id3frame_names[index];
        field = frame->GetField (ID3FN_TEXT);
        if (field) 
            if (field->Get (buffer, sizeof buffer) > 0) {
                pairs.insert(make_pair(id3tag, string(buffer)));
                //cout << "id3lib (" << id3tag <<':' << buffer <<')' << endl;
            }
    }

    delete ti;
    return true;
}

bool ID3lib::writeMetadata(const std::string&url, map_type& pairs)
{
    // Rewrite in terms of tags.  Using standard names.
    return false;
}



/* arch-tag: 8c57c4f2-69fc-441b-88aa-7310a01d2826
   (do not change this comment) */

Generated by  Doxygen 1.6.0   Back to index