"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/tagutils/tagutils.c" (24 Nov 2020, 9565 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tagutils.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.1_vs_1.3.0.

    1 //=========================================================================
    2 // FILENAME : tagutils.c
    3 // DESCRIPTION  : MP3/MP4/Ogg/FLAC metadata reader
    4 //=========================================================================
    5 // Copyright (c) 2008- NETGEAR, Inc. All Rights Reserved.
    6 //=========================================================================
    7 
    8 /* This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
   10  * the Free Software Foundation; either version 2 of the License, or
   11  * (at your option) any later version.
   12  *
   13  * This program is distributed in the hope that it will be useful,
   14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  * GNU General Public License for more details.
   17  *
   18  * You should have received a copy of the GNU General Public License
   19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
   20  */
   21 
   22 /* This file is derived from mt-daapd project */
   23 
   24 #include "config.h"
   25 #include <ctype.h>
   26 #include <errno.h>
   27 #include <id3tag.h>
   28 #include <stdlib.h>
   29 #include <stddef.h>
   30 #include <string.h>
   31 #include <fcntl.h>
   32 #include <unistd.h>
   33 #include <time.h>
   34 #include <sys/time.h>
   35 #include <netinet/in.h>
   36 #ifdef HAVE_VORBISFILE
   37 #include <ogg/ogg.h>
   38 #include <vorbis/codec.h>
   39 #endif
   40 #include <FLAC/metadata.h>
   41 
   42 #ifdef HAVE_ICONV
   43 #include <iconv.h>
   44 #endif
   45 #include <sqlite3.h>
   46 #include "tagutils.h"
   47 #include "../metadata.h"
   48 #include "../utils.h"
   49 #include "../log.h"
   50 
   51 struct id3header {
   52     unsigned char id[3];
   53     unsigned char version[2];
   54     unsigned char flags;
   55     unsigned char size[4];
   56 } __attribute((packed));
   57 
   58 char *winamp_genre[] = {
   59     /*00*/ "Blues",             "Classic Rock",     "Country",           "Dance",
   60            "Disco",             "Funk",             "Grunge",            "Hip-Hop",
   61     /*08*/ "Jazz",              "Metal",            "New Age",           "Oldies",
   62            "Other",             "Pop",              "R&B",               "Rap",
   63     /*10*/ "Reggae",            "Rock",             "Techno",            "Industrial",
   64            "Alternative",       "Ska",              "Death Metal",       "Pranks",
   65     /*18*/ "Soundtrack",        "Euro-Techno",  "Ambient",           "Trip-Hop",
   66            "Vocal",             "Jazz+Funk",        "Fusion",            "Trance",
   67     /*20*/ "Classical",         "Instrumental",     "Acid",              "House",
   68            "Game",              "Sound Clip",       "Gospel",            "Noise",
   69     /*28*/ "AlternRock",        "Bass",             "Soul",              "Punk",
   70            "Space",             "Meditative",       "Instrumental Pop",  "Instrumental Rock",
   71     /*30*/ "Ethnic",            "Gothic",       "Darkwave",          "Techno-Industrial",
   72            "Electronic",        "Pop-Folk",         "Eurodance",         "Dream",
   73     /*38*/ "Southern Rock",     "Comedy",           "Cult",              "Gangsta",
   74            "Top 40",            "Christian Rap",    "Pop/Funk",          "Jungle",
   75     /*40*/ "Native American",   "Cabaret",          "New Wave",          "Psychedelic",
   76            "Rave",              "Showtunes",        "Trailer",           "Lo-Fi",
   77     /*48*/ "Tribal",            "Acid Punk",        "Acid Jazz",         "Polka",
   78            "Retro",             "Musical",          "Rock & Roll",       "Hard Rock",
   79     /*50*/ "Folk",              "Folk/Rock",        "National folk",     "Swing",
   80            "Fast-fusion",       "Bebob",            "Latin",             "Revival",
   81     /*58*/ "Celtic",            "Bluegrass",        "Avantgarde",        "Gothic Rock",
   82            "Progressive Rock",  "Psychedelic Rock", "Symphonic Rock",    "Slow Rock",
   83     /*60*/ "Big Band",          "Chorus",           "Easy Listening",    "Acoustic",
   84            "Humour",            "Speech",           "Chanson",           "Opera",
   85     /*68*/ "Chamber Music",     "Sonata",           "Symphony",          "Booty Bass",
   86            "Primus",            "Porn Groove",      "Satire",            "Slow Jam",
   87     /*70*/ "Club",              "Tango",            "Samba",             "Folklore",
   88            "Ballad",            "Powder Ballad",    "Rhythmic Soul",     "Freestyle",
   89     /*78*/ "Duet",              "Punk Rock",        "Drum Solo",         "A Capella",
   90            "Euro-House",        "Dance Hall",       "Goa",               "Drum & Bass",
   91     /*80*/ "Club House",        "Hardcore",         "Terror",            "Indie",
   92            "BritPop",           "NegerPunk",        "Polsk Punk",        "Beat",
   93     /*88*/ "Christian Gangsta", "Heavy Metal",      "Black Metal",       "Crossover",
   94            "Contemporary C",    "Christian Rock",   "Merengue",          "Salsa",
   95     /*90*/ "Thrash Metal",      "Anime",            "JPop",              "SynthPop",
   96            "Unknown"
   97 };
   98 
   99 #define WINAMP_GENRE_UNKNOWN ((sizeof(winamp_genre) / sizeof(winamp_genre[0])) - 1)
  100 
  101 
  102 /*
  103  * Prototype
  104  */
  105 #include "tagutils-mp3.h"
  106 #include "tagutils-aac.h"
  107 #ifdef HAVE_VORBISFILE
  108 #include "tagutils-ogg.h"
  109 #endif
  110 #include "tagutils-flc.h"
  111 #include "tagutils-asf.h"
  112 #include "tagutils-wav.h"
  113 #include "tagutils-pcm.h"
  114 #include "tagutils-dsf.h"
  115 #include "tagutils-dff.h"
  116 
  117 static int _get_tags(char *file, struct song_metadata *psong);
  118 static int _get_fileinfo(char *file, struct song_metadata *psong);
  119 
  120 
  121 /*
  122  * Typedefs
  123  */
  124 
  125 typedef struct {
  126     char* type;
  127     int (*get_tags)(char* file, struct song_metadata* psong);
  128     int (*get_fileinfo)(char* file, struct song_metadata* psong);
  129 } taghandler;
  130 
  131 static taghandler taghandlers[] = {
  132     { "aac", _get_aactags,  _get_aacfileinfo },
  133     { "mp3", _get_mp3tags,  _get_mp3fileinfo },
  134     { "flc", _get_flctags,  _get_flcfileinfo },
  135 #ifdef HAVE_VORBISFILE
  136     { "ogg", NULL,      _get_oggfileinfo },
  137 #endif
  138     { "asf", NULL,      _get_asffileinfo },
  139     { "wav", _get_wavtags,  _get_wavfileinfo },
  140     { "pcm", NULL,      _get_pcmfileinfo },
  141     { "dsf", _get_dsftags,  _get_dsffileinfo },
  142     { "dff", NULL,      _get_dfffileinfo },
  143     { NULL,  NULL, NULL }
  144 };
  145 
  146 
  147 
  148 //*********************************************************************************
  149 #include "tagutils-misc.c"
  150 #include "tagutils-mp3.c"
  151 #include "tagutils-aac.c"
  152 #ifdef HAVE_VORBISFILE
  153 #include "tagutils-ogg.c"
  154 #endif
  155 #include "tagutils-flc.c"
  156 #include "tagutils-asf.c"
  157 #include "tagutils-wav.c"
  158 #include "tagutils-pcm.c"
  159 #include "tagutils-plist.c"
  160 #include "tagutils-dsf.c"
  161 #include "tagutils-dff.c"
  162 
  163 //*********************************************************************************
  164 // freetags()
  165 #define MAYBEFREE(a) { if((a)) free((a)); };
  166 void
  167 freetags(struct song_metadata *psong)
  168 {
  169     int role;
  170 
  171     MAYBEFREE(psong->path);
  172     MAYBEFREE(psong->image);
  173     MAYBEFREE(psong->title);
  174     MAYBEFREE(psong->album);
  175     MAYBEFREE(psong->genre);
  176     MAYBEFREE(psong->comment);
  177     for(role = ROLE_START; role <= ROLE_LAST; role++)
  178     {
  179         MAYBEFREE(psong->contributor[role]);
  180         MAYBEFREE(psong->contributor_sort[role]);
  181     }
  182     MAYBEFREE(psong->grouping);
  183     MAYBEFREE(psong->mime);
  184     MAYBEFREE(psong->dlna_pn);
  185     MAYBEFREE(psong->tagversion);
  186     MAYBEFREE(psong->musicbrainz_albumid);
  187     MAYBEFREE(psong->musicbrainz_trackid);
  188     MAYBEFREE(psong->musicbrainz_artistid);
  189     MAYBEFREE(psong->musicbrainz_albumartistid);
  190 }
  191 
  192 // _get_fileinfo
  193 static int
  194 _get_fileinfo(char *file, struct song_metadata *psong)
  195 {
  196     taghandler *hdl;
  197 
  198     // dispatch to appropriate tag handler
  199     for(hdl = taghandlers; hdl->type; ++hdl)
  200         if(!strcmp(hdl->type, psong->type))
  201             break;
  202 
  203     if(hdl->get_fileinfo)
  204         return hdl->get_fileinfo(file, psong);
  205 
  206     return 0;
  207 }
  208 
  209 
  210 static void
  211 _make_composite_tags(struct song_metadata *psong)
  212 {
  213     int len;
  214 
  215     len = 1;
  216 
  217     if(!psong->contributor[ROLE_ARTIST] &&
  218        (psong->contributor[ROLE_BAND] || psong->contributor[ROLE_CONDUCTOR]))
  219     {
  220         if(psong->contributor[ROLE_BAND])
  221             len += strlen(psong->contributor[ROLE_BAND]);
  222         if(psong->contributor[ROLE_CONDUCTOR])
  223             len += strlen(psong->contributor[ROLE_CONDUCTOR]);
  224 
  225         len += 3;
  226 
  227         psong->contributor[ROLE_ARTIST] = (char*)calloc(len, 1);
  228         if(psong->contributor[ROLE_ARTIST])
  229         {
  230             if(psong->contributor[ROLE_BAND])
  231                 strcat(psong->contributor[ROLE_ARTIST], psong->contributor[ROLE_BAND]);
  232 
  233             if(psong->contributor[ROLE_BAND] && psong->contributor[ROLE_CONDUCTOR])
  234                 strcat(psong->contributor[ROLE_ARTIST], " - ");
  235 
  236             if(psong->contributor[ROLE_CONDUCTOR])
  237                 strcat(psong->contributor[ROLE_ARTIST], psong->contributor[ROLE_CONDUCTOR]);
  238         }
  239     }
  240 
  241 #if 0 // already taken care of by scanner.c
  242     if(!psong->title)
  243     {
  244         char *suffix;
  245         psong->title = strdup(psong->basename);
  246         suffix = strrchr(psong->title, '.');
  247         if(suffix) *suffix = '\0';
  248     }
  249 #endif
  250 }
  251 
  252 
  253 /*****************************************************************************/
  254 // _get_tags
  255 static int
  256 _get_tags(char *file, struct song_metadata *psong)
  257 {
  258     taghandler *hdl;
  259 
  260     // dispatch
  261     for(hdl = taghandlers ; hdl->type ; ++hdl)
  262         if(!strcasecmp(hdl->type, psong->type))
  263             break;
  264 
  265     if(hdl->get_tags)
  266     {
  267         return hdl->get_tags(file, psong);
  268     }
  269 
  270     return 0;
  271 }
  272 
  273 /*****************************************************************************/
  274 // readtags
  275 int
  276 readtags(char *path, struct song_metadata *psong, struct stat *stat, char *lang, char *type)
  277 {
  278     char *fname;
  279 
  280     if(lang_index == -1)
  281         lang_index = _lang2cp(lang);
  282 
  283     memset((void*)psong, 0, sizeof(struct song_metadata));
  284     psong->path = strdup(path);
  285     psong->type = type;
  286 
  287     fname = strrchr(psong->path, '/');
  288     psong->basename = fname ? fname + 1 : psong->path;
  289 
  290     if(stat)
  291     {
  292         if(!psong->time_modified)
  293             psong->time_modified = stat->st_mtime;
  294         psong->file_size = stat->st_size;
  295     }
  296 
  297     // get tag
  298     if( _get_tags(path, psong) == 0 )
  299     {
  300         _make_composite_tags(psong);
  301     }
  302     
  303     // get fileinfo
  304     return _get_fileinfo(path, psong);
  305 }