Sigrid Solveig Haflínudóttirfix warnings6bc6a9b3 years agoHistory
227 lines · 6.0 KB · C
RawDownload
/* libSoX MP3 utilities  Copyright (c) 2007-9 SoX contributors * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This library 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA */ #include "sox_i.h"#include "id3.h" #ifdef HAVE_ID3TAG #include <id3tag.h> static char const * id3tagmap[][2] ={  {"TIT2", "Title"},  {"TPE1", "Artist"},  {"TALB", "Album"},  {"TCOM", "Composer"},  {"TRCK", "Tracknumber"},  {"TDRC", "Year"},  {"TCON", "Genre"},  {"COMM", "Comment"},  {"TPOS", "Discnumber"},  {NULL, NULL}}; static id3_utf8_t * utf8_id3tag_findframe(    struct id3_tag * tag, const char * const frameid, unsigned index){  struct id3_frame const * frame = id3_tag_findframe(tag, frameid, index);  if (frame) {    unsigned nfields = frame->nfields;     while (nfields--) {      union id3_field const *field = id3_frame_field(frame, nfields);      int ftype = id3_field_type(field);      const id3_ucs4_t *ucs4 = NULL;      unsigned nstrings;       switch (ftype) {      case ID3_FIELD_TYPE_STRING:        ucs4 = id3_field_getstring(field);        break;       case ID3_FIELD_TYPE_STRINGFULL:        ucs4 = id3_field_getfullstring(field);        break;       case ID3_FIELD_TYPE_STRINGLIST:        nstrings = id3_field_getnstrings(field);        while (nstrings--) {          ucs4 = id3_field_getstrings(field, nstrings);          if (ucs4)            break;        }        break;      }       if (ucs4)        return id3_ucs4_utf8duplicate(ucs4); /* Must call free() on this */    }  }  return NULL;} struct tag_info_node{    struct tag_info_node * next;    off_t start;    off_t end;}; struct tag_info {  sox_format_t * ft;  struct tag_info_node * head;  struct id3_tag * tag;}; static int add_tag(struct tag_info * info){  struct tag_info_node * current;  off_t start, end;  id3_byte_t query[ID3_TAG_QUERYSIZE];  id3_byte_t * buffer;  long size;  int result = 0;   /* Ensure we're at the start of a valid tag and get its size. */  if (ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) ||      !(size = id3_tag_query(query, ID3_TAG_QUERYSIZE))) {    return 0;  }  if (size < 0) {    if (0 != lsx_seeki(info->ft, size, SEEK_CUR) ||        ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) ||        (size = id3_tag_query(query, ID3_TAG_QUERYSIZE)) <= 0) {      return 0;    }  }   /* Don't read a tag more than once. */  start = lsx_tell(info->ft);  end = start + size;  for (current = info->head; current; current = current->next) {    if (start == current->start && end == current->end) {      return 1;    } else if (start < current->end && current->start < end) {      return 0;    }  }   buffer = lsx_malloc((size_t)size);  if (!buffer) {    return 0;  }  memcpy(buffer, query, ID3_TAG_QUERYSIZE);  if ((unsigned long)size - ID3_TAG_QUERYSIZE ==      lsx_readbuf(info->ft, buffer + ID3_TAG_QUERYSIZE, (size_t)size - ID3_TAG_QUERYSIZE)) {    struct id3_tag * tag = id3_tag_parse(buffer, (size_t)size);    if (tag) {      current = lsx_malloc(sizeof(struct tag_info_node));      if (current) {        current->next = info->head;        current->start = start;        current->end = end;        info->head = current;        if (info->tag && (info->tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) {          struct id3_frame * frame;          unsigned i;          for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); i++) {            id3_tag_attachframe(info->tag, frame);          }          id3_tag_delete(tag);        } else {          if (info->tag) {            id3_tag_delete(info->tag);          }          info->tag = tag;        }      }    }  }  free(buffer);  return result;} void lsx_id3_read_tag(sox_format_t * ft, sox_bool search){  struct tag_info   info;  id3_utf8_t        * utf8;  int               i;  int               has_id3v1 = 0;   info.ft = ft;  info.head = NULL;  info.tag = NULL;   /*  We look for:  ID3v1 at end (EOF - 128).  ID3v2 at start.  ID3v2 at end (but before ID3v1 from end if there was one).  */   if (search) {    if (0 == lsx_seeki(ft, -128, SEEK_END)) {      has_id3v1 =        add_tag(&info) &&        1 == ID3_TAG_VERSION_MAJOR(id3_tag_version(info.tag));    }    if (0 == lsx_seeki(ft, 0, SEEK_SET)) {      add_tag(&info);    }    if (0 == lsx_seeki(ft, has_id3v1 ? -138 : -10, SEEK_END)) {      add_tag(&info);    }  } else {    add_tag(&info);  }   if (info.tag && info.tag->frames) {    for (i = 0; id3tagmap[i][0]; ++i) {      if ((utf8 = utf8_id3tag_findframe(info.tag, id3tagmap[i][0], 0))) {        char * comment = lsx_malloc(strlen(id3tagmap[i][1]) + 1 + strlen((char *)utf8) + 1);        sprintf(comment, "%s=%s", id3tagmap[i][1], utf8);        sox_append_comment(&ft->oob.comments, comment);        free(comment);        free(utf8);      }    }    if ((utf8 = utf8_id3tag_findframe(info.tag, "TLEN", 0))) {      unsigned long tlen = strtoul((char *)utf8, NULL, 10);      if (tlen > 0 && tlen < ULONG_MAX) {        ft->signal.length= tlen; /* In ms; convert to samples later */        lsx_debug("got exact duration from ID3 TLEN");      }      free(utf8);    }  }  while (info.head) {    struct tag_info_node * head = info.head;    info.head = head->next;    free(head);  }  if (info.tag) {    id3_tag_delete(info.tag);  }} #else /* Stub for format modules */void lsx_id3_read_tag(sox_format_t *ft, sox_bool search) { USED(ft); USED(search); } #endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t