/**
 * Import a "Comment frame" (ID3v2.4.0 section 4.10).  It
 * contains 4 fields:
 *
 * - encoding
 * - language
 * - string
 * - full string (we use this one)
 */
static void
tag_id3_import_comment(struct tag *dest, struct id3_tag *tag, const char *id,
		       enum tag_type type)
{
	struct id3_frame const *frame;
	id3_ucs4_t const *ucs4;
	id3_utf8_t *utf8;
	union id3_field const *field;

	frame = id3_tag_findframe(tag, id, 0);
	if (frame == NULL || frame->nfields != 4)
		return;

	/* for now I only read the 4th field, with the fullstring */
	field = id3_frame_field(frame, 3);
	if (field == NULL)
		return;

	ucs4 = id3_field_getfullstring(field);
	if (ucs4 == NULL)
		return;

	utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
	if (utf8 == NULL)
		return;

	tag_add_item(dest, type, (char *)utf8);
	g_free(utf8);
}
Beispiel #2
0
const id3_ucs4_t* id3_metadata_getcomment(const struct id3_tag* tag, enum id3_field_textencoding* encoding)
{
  union id3_field const *field;
  struct id3_frame const *frame;
  const id3_ucs4_t* ucs4 = 0;
  int commentNumber = 0;

  // return the first non-empty comment
  do
  {
    frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, commentNumber++);
    if (frame == 0)
	    return id3_ucs4_empty;

    *encoding = id3_field_gettextencoding(id3_frame_field(frame, 0));

    field = id3_frame_field(frame, 3);
    if (field == 0)
      return id3_ucs4_empty;
    
    ucs4 = id3_field_getfullstring(field);
    if (!ucs4)
      return id3_ucs4_empty;
  }
  while (*ucs4 == 0);
  return ucs4;
}
Beispiel #3
0
const id3_ucs4_t* id3_metadata_getcomment(const struct id3_tag* tag, enum id3_field_textencoding* encoding)
{
  union id3_field const *field;
  struct id3_frame const *frame;
  int commentNumber = 0;
  const id3_ucs4_t* ucs4 = 0;

  // return the first non-empty comment
  do
  {
    frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, commentNumber++);

    if (frame && frame->nfields == 4)
    {
      //get short description
      field = id3_frame_field(frame, 2);
      if (field == 0)
        continue;
      
      ucs4 = id3_field_getstring(field);

      // Multiple values are allowed per comment field, but storing different comment
      // frames requires a different description for each frame. The first COMM frame
      // encountered without a description will be used as the comment field.
      // Source http://puddletag.sourceforge.net/source/id3.html
      if (ucs4 && *ucs4 == 0)//if short description on this frame is empty - consider this the wanted comment frame
      {
        //fetch encoding of the frame
        field = id3_frame_field(frame, 0);
        
        if(field == 0)
          continue;
          
        *encoding = id3_field_gettextencoding(field);

        //finally fetch the comment
        field = id3_frame_field(frame, 3);
        if (field == 0)
          continue;
    
        return id3_field_getfullstring(field);
      }
    }
  }
  while (frame);
  return ucs4;
}
Beispiel #4
0
static
void v1_renderstr(struct id3_tag const *tag, char const *frameid,
		  id3_byte_t **buffer, id3_length_t length)
{
  struct id3_frame *frame;
  id3_ucs4_t const *string;

  frame = id3_tag_findframe(tag, frameid, 0);
  if (frame == 0)
    string = id3_ucs4_empty;
  else {
    if (strcmp(frameid, ID3_FRAME_COMMENT) == 0)
      string = id3_field_getfullstring(&frame->fields[3]);
    else
      string = id3_field_getstrings(&frame->fields[1], 0);
  }

  id3_render_paddedstring(buffer, string, length);
}
Beispiel #5
0
wchar_t* GetMP3Tag(const id3_tag* tag, const char* name)
{
	wchar_t* content = NULL;
	id3_frame* frame = id3_tag_findframe(tag, name, 0);
	if (frame != NULL)
	{
		id3_field* field = id3_frame_field(frame, 0);
		id3_field_textencoding encoding = id3_field_gettextencoding(field);
		field = id3_frame_field(frame, 1);

		switch (id3_field_type(field))
		{
		case ID3_FIELD_TYPE_STRING:
			content = GetMP3Text(encoding, field, id3_field_getstring(field));
			break;

		case ID3_FIELD_TYPE_STRINGFULL:						
			content = GetMP3Text(encoding, field, id3_field_getfullstring(field));
			break;

		case ID3_FIELD_TYPE_STRINGLIST:
			{				
				DWORD dataLength = 0, bufferLength = 0;
				unsigned int n = id3_field_getnstrings(field);
				for (unsigned int i = 0; i < n; i++)
				{
					wchar_t* p = GetMP3Text(encoding, field, id3_field_getstrings(field, i));
					if (p == NULL)
						continue;

					AppendBuffer((char**)&content, dataLength, bufferLength, (const char*)p, wcslen(p) * 2 + 1);
					SAFE_DELETE_ARRAY(p);
				}
			}
			break;
		}
	}

	return content;
}
Beispiel #6
0
wxString GetID3FieldStr(struct id3_tag *tp, const char *name)
{
   struct id3_frame *frame;

   frame = id3_tag_findframe(tp, name, 0);
   if (frame) {
      const id3_ucs4_t *ustr;

      if (strcmp(name, ID3_FRAME_COMMENT) == 0)
	 ustr = id3_field_getfullstring(&frame->fields[3]);
      else
	 ustr = id3_field_getstrings(&frame->fields[1], 0);

      if (ustr) {
	 char *str = (char *)id3_ucs4_utf8duplicate(ustr);
	 wxString s = UTF8CTOWX(str);
	 free(str);
	 return s;
      }
   }

   return wxT("");
}
Beispiel #7
0
/* Convenience for retrieving already formatted id3 data
 * what parameter is one of
 *  ID3_FRAME_TITLE
 *  ID3_FRAME_ARTIST
 *  ID3_FRAME_ALBUM
 *  ID3_FRAME_YEAR
 *  ID3_FRAME_COMMENT
 *  ID3_FRAME_GENRE
 * It allocates a new string. Free it later.
 * NULL if no tag or error.
 */
char *id3_get_tag (struct id3_tag const *tag, char const *what, unsigned int maxlen)
{
    struct id3_frame const *frame = NULL;
    union id3_field const *field = NULL;
    int nstrings;
    int avail;
    int j;
    int tocopy;
    int len;
    char printable [1024];
    char *retval = NULL;
    id3_ucs4_t const *ucs4 = NULL;
    id3_latin1_t *latin1 = NULL;

    memset (printable, '\0', 1024);
    avail = 1024;
    if (strcmp (what, ID3_FRAME_COMMENT) == 0)
    {
        /*There may be sth wrong. I did not fully understand how to use
            libid3tag for retrieving comments  */
        j=0;
        frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, j++);
        if (!frame) return (NULL);
        ucs4 = id3_field_getfullstring (&frame->fields[3]);
        if (!ucs4) return (NULL);
        latin1 = id3_ucs4_latin1duplicate (ucs4);
        if (!latin1 || strlen(latin1) == 0) return (NULL);
        len = strlen(latin1);
        if (avail > len)
            tocopy = len;
        else
            tocopy = 0;
        if (!tocopy) return (NULL);
        avail-=tocopy;
        strncat (printable, latin1, tocopy);
        free (latin1);
    }
    
    else
    {
        frame = id3_tag_findframe (tag, what, 0);
        if (!frame) return (NULL);
        field = &frame->fields[1];
        nstrings = id3_field_getnstrings(field);
        for (j=0; j<nstrings; ++j)
        {
            ucs4 = id3_field_getstrings(field, j);
            if (!ucs4) return (NULL);
            if (strcmp (what, ID3_FRAME_GENRE) == 0)
                ucs4 = id3_genre_name(ucs4);
            latin1 = id3_ucs4_latin1duplicate(ucs4);
            if (!latin1) break;
            len = strlen(latin1);
            if (avail > len)
                tocopy = len;
            else
                tocopy = 0;
            if (!tocopy) break;
            avail-=tocopy;
            strncat (printable, latin1, tocopy);
            free (latin1);
        }
    }
    retval = malloc (maxlen + 1);
    if (!retval) return (NULL);

    strncpy (retval, printable, maxlen);
    retval[maxlen] = '\0';

    len = strlen(printable);
    if (maxlen > len)
    {
        memset (retval + len, ' ', maxlen - len);
    }

    return (retval);
}
Beispiel #8
0
static int
_get_dsftags(char *file, struct song_metadata *psong)
{
	struct id3_tag *pid3tag;
	struct id3_frame *pid3frame;
	int err;
	int index;
	int used;
	unsigned char *utf8_text;
	int genre = WINAMP_GENRE_UNKNOWN;
	int have_utf8;
	int have_text;
	id3_ucs4_t const *native_text;
	char *tmp;
	int got_numeric_genre;
	id3_byte_t const *image;
	id3_length_t image_size = 0;
	
	FILE *fp;
	struct id3header *pid3;
	uint32_t len;
	unsigned char hdr[28] = {0};
	uint64_t total_size = 0;
	uint64_t pointer_to_metadata_chunk = 0;
	uint64_t metadata_chunk_size = 0;
	unsigned char *id3tagbuf = NULL;

	//DEBUG DPRINTF(E_DEBUG,L_SCANNER,"Getting DSF file info\n");

	if((fp = fopen(file, "rb")) == NULL)
	{
		DPRINTF(E_WARN, L_SCANNER, "Could not create file handle\n");
		return -1;
	}

	len = 28;
	if(!(len = fread(hdr, len, 1,fp)))
	{
		DPRINTF(E_WARN, L_SCANNER, "Could not read DSD Chunk from %s\n", file);
		fclose(fp);
		return -1;
	}

	if(strncmp((char*)hdr, "DSD ", 4))
	{
		DPRINTF(E_WARN, L_SCANNER, "Invalid DSD Chunk header in %s\n", file);
		fclose(fp);
		return -1;
	}

	total_size = GET_DSF_INT64(hdr + 12);
	pointer_to_metadata_chunk = GET_DSF_INT64(hdr + 20);
	
	//DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", total_size);
	//DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", pointer_to_metadata_chunk);
	//DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", metadata_chunk_size);

	//check invalid metadata
	if(total_size == 0)
	{
		fclose(fp);
		DPRINTF(E_INFO, L_SCANNER, "Invalid TotalDataSize in %s\n", file);
		return 0;
	}

	if(pointer_to_metadata_chunk == 0)
	{
		fclose(fp);
		DPRINTF(E_INFO, L_SCANNER, "Metadata doesn't exist %s\n", file);
		return 0;
	}

	if(total_size > pointer_to_metadata_chunk)
	{
		metadata_chunk_size = total_size - pointer_to_metadata_chunk;
	}
	else
	{
		fclose(fp);
		DPRINTF(E_INFO, L_SCANNER, "Invalid PointerToMetadata in %s\n", file);
		return 0;
	}

	fseeko(fp, pointer_to_metadata_chunk,SEEK_SET);

	id3tagbuf = (unsigned char *)malloc(sizeof(unsigned char)*metadata_chunk_size);
	if(id3tagbuf == NULL)
	{
		fclose(fp);
		DPRINTF(E_WARN, L_SCANNER, "Out of memory.Big MetadataSize in %s\n",file);
		return -1;
	}
	memset(id3tagbuf, 0,sizeof(unsigned char)*metadata_chunk_size);
	
	if(!(len = fread(id3tagbuf,metadata_chunk_size,1,fp)))
	{
		fclose(fp);
		free(id3tagbuf);
		DPRINTF(E_WARN, L_SCANNER, "Could not read Metadata Chunk from %s\n", file);
		return -1;
	}
	
	pid3tag = id3_tag_parse(id3tagbuf,metadata_chunk_size);
	
	if(!pid3tag)
	{
		free(id3tagbuf);
		err = errno;
		errno = err;
		DPRINTF(E_WARN, L_SCANNER, "Cannot get ID3 tag for %s\n", file);
		return -1;
	}

	pid3 = (struct id3header*)id3tagbuf;

	if(strncmp((char*)pid3->id, "ID3", 3) == 0)
	{
		char tagversion[16];

		/* found an ID3 header... */
		snprintf(tagversion, sizeof(tagversion), "ID3v2.%d.%d",
			 pid3->version[0], pid3->version[1]);
		psong->tagversion = strdup(tagversion);
	}
	pid3 = NULL;
	
	index = 0;
	while((pid3frame = id3_tag_findframe(pid3tag, "", index)))
	{
		used = 0;
		utf8_text = NULL;
		native_text = NULL;
		have_utf8 = 0;
		have_text = 0;

		if(!strcmp(pid3frame->id, "YTCP"))   /* for id3v2.2 */
		{
			psong->compilation = 1;
			DPRINTF(E_DEBUG, L_SCANNER, "Compilation: %d [%s]\n", psong->compilation, basename(file));
		}
		else if(!strcmp(pid3frame->id, "APIC") && !image_size)
		{
			if( (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpeg") == 0) ||
			    (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpg") == 0) ||
			    (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "jpeg") == 0) )
			{
				image = id3_field_getbinarydata(&pid3frame->fields[4], &image_size);
				if( image_size )
				{
					psong->image = malloc(image_size);
					memcpy(psong->image, image, image_size);
					psong->image_size = image_size;
					//DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size);
				}
			}
		}

		if(((pid3frame->id[0] == 'T') || (strcmp(pid3frame->id, "COMM") == 0)) &&
		   (id3_field_getnstrings(&pid3frame->fields[1])))
			have_text = 1;

		if(have_text)
		{
			native_text = id3_field_getstrings(&pid3frame->fields[1], 0);

			if(native_text)
			{
				have_utf8 = 1;
				if(lang_index >= 0)
					utf8_text = _get_utf8_text(native_text); // through iconv
				else
					utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);

				if(!strcmp(pid3frame->id, "TIT2"))
				{
					used = 1;
					psong->title = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPE1"))
				{
					used = 1;
					psong->contributor[ROLE_ARTIST] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TALB"))
				{
					used = 1;
					psong->album = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TCOM"))
				{
					used = 1;
					psong->contributor[ROLE_COMPOSER] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TIT1"))
				{
					used = 1;
					psong->grouping = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPE2"))
				{
					used = 1;
					psong->contributor[ROLE_BAND] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPE3"))
				{
					used = 1;
					psong->contributor[ROLE_CONDUCTOR] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TCON"))
				{
					used = 1;
					psong->genre = (char*)utf8_text;
					got_numeric_genre = 0;
					if(psong->genre)
					{
						if(!strlen(psong->genre))
						{
							genre = WINAMP_GENRE_UNKNOWN;
							got_numeric_genre = 1;
						}
						else if(isdigit(psong->genre[0]))
						{
							genre = atoi(psong->genre);
							got_numeric_genre = 1;
						}
						else if((psong->genre[0] == '(') && (isdigit(psong->genre[1])))
						{
							genre = atoi((char*)&psong->genre[1]);
							got_numeric_genre = 1;
						}

						if(got_numeric_genre)
						{
							if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
								genre = WINAMP_GENRE_UNKNOWN;
							free(psong->genre);
							psong->genre = strdup(winamp_genre[genre]);
						}
					}
				}
				else if(!strcmp(pid3frame->id, "COMM"))
				{
					used = 1;
					psong->comment = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPOS"))
				{
					tmp = (char*)utf8_text;
					strsep(&tmp, "/");
					if(tmp)
					{
						psong->total_discs = atoi(tmp);
					}
					psong->disc = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TRCK"))
				{
					tmp = (char*)utf8_text;
					strsep(&tmp, "/");
					if(tmp)
					{
						psong->total_tracks = atoi(tmp);
					}
					psong->track = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TDRC"))
				{
					psong->year = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TLEN"))
				{
					psong->song_length = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TBPM"))
				{
					psong->bpm = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TCMP"))
				{
					psong->compilation = (char)atoi((char*)utf8_text);
				}
			}
		}

		// check if text tag
		if((!used) && (have_utf8) && (utf8_text))
			free(utf8_text);

		// v2 COMM
		if((!strcmp(pid3frame->id, "COMM")) && (pid3frame->nfields == 4))
		{
			native_text = id3_field_getstring(&pid3frame->fields[2]);
			if(native_text)
			{
				utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
				if((utf8_text) && (strncasecmp((char*)utf8_text, "iTun", 4) != 0))
				{
					// read comment
					free(utf8_text);

					native_text = id3_field_getfullstring(&pid3frame->fields[3]);
					if(native_text)
					{
						utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
						if(utf8_text)
						{
							free(psong->comment);
							psong->comment = (char*)utf8_text;
						}
					}
				}
				else
				{
					free(utf8_text);
				}
			}
		}

		index++;
	}

	id3_tag_delete(pid3tag);
	free(id3tagbuf);
	fclose(fp);
	//DPRINTF(E_DEBUG, L_SCANNER, "Got id3tag successfully for file=%s\n", file);
	return 0;
}
Beispiel #9
0
void MP3ImportFileHandle::ImportID3(Tags *tags)
{
#ifdef USE_LIBID3TAG 
   struct id3_file *fp = id3_file_open(OSFILENAME(mFilename), ID3_FILE_MODE_READONLY);
   if (!fp) {
      return;
   }

   struct id3_tag *tp = id3_file_tag(fp);
   if (!tp) {
      id3_file_close(fp);
      return;
   }

   tags->Clear();
   tags->SetID3V2( tp->options & ID3_TAG_OPTION_ID3V1 ? false : true );

   // Loop through all frames
   for (int i = 0; i < (int) tp->nframes; i++) {
      struct id3_frame *frame = tp->frames[i];

      // printf("ID: %08x '%4s'\n", (int) *(int *)frame->id, frame->id);
      // printf("Desc: %s\n", frame->description);
      // printf("Num fields: %d\n", frame->nfields);

      // for (int j = 0; j < (int) frame->nfields; j++) {
      //    printf("field %d type %d\n", j, frame->fields[j].type );
      //    if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST) {
      //       printf("num strings %d\n", frame->fields[j].stringlist.nstrings);
      //    }
      // }

      wxString n, v;

      // Determine the tag name
      if (strcmp(frame->id, ID3_FRAME_TITLE) == 0) {
         n = TAG_TITLE;
      }
      else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0) {
         n = TAG_ARTIST;
      }
      else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0) {
         n = TAG_ALBUM;
      }
      else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0) {
         n = TAG_TRACK;
      }
      else if (strcmp(frame->id, "TYER") == 0) {
         n = TAG_YEAR;
      }
      else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0) {
         n = TAG_YEAR;
      }
      else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0) {
         n = TAG_COMMENTS;
      }
      else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0) {
         n = TAG_GENRE;
      }
   else {
         // Use frame description as default tag name.  The descriptions
         // may include several "meanings" separated by "/" characters, so
         // we just use the first meaning
         n = UTF8CTOWX(frame->description).BeforeFirst(wxT('/'));
      }

      const id3_ucs4_t *ustr = NULL;

      if (n == TAG_COMMENTS) {
         ustr = id3_field_getfullstring(&frame->fields[3]);
      }
      else if (frame->nfields == 3) {
         ustr = id3_field_getstring(&frame->fields[1]);
         if (ustr) {
            char *str = (char *)id3_ucs4_utf8duplicate(ustr);
            n = UTF8CTOWX(str);
            free(str);
         }

         ustr = id3_field_getstring(&frame->fields[2]);
      }
      else if (frame->nfields >= 2) {
         ustr = id3_field_getstrings(&frame->fields[1], 0);
      }

      if (ustr) {
         char *str = (char *)id3_ucs4_utf8duplicate(ustr);
         v = UTF8CTOWX(str);
         free(str);
      }

      if (!n.IsEmpty() && !v.IsEmpty()) {
         tags->SetTag(n, v);
   }
}

   // Convert v1 genre to name
   if (tags->HasTag(TAG_GENRE)) {
      long g = -1;
      if (tags->GetTag(TAG_GENRE).ToLong(&g)) {
         tags->SetTag(TAG_GENRE, tags->GetGenre(g));
   }
}

   id3_file_close(fp);
#endif // ifdef USE_LIBID3TAG 
}
Beispiel #10
0
/*
 * NAME:  show_id3()
 * DESCRIPTION: display an ID3 tag
 */
static
void show_id3(playa_info_t * info3, struct id3_tag const *tag)
{
  unsigned int i;
  struct id3_frame const *frame;
  id3_ucs4_t const *ucs4;
  id3_latin1_t *latin1;

  /* $$$  Care of order in mp3dc.h */
  struct {
    char const *id;
    char const *name;
  } const info[] = {
    {ID3_FRAME_ARTIST, N_("Artist")},
    {ID3_FRAME_ALBUM, N_("Album")},
    {ID3_FRAME_TRACK, N_("Track")},
    {ID3_FRAME_TITLE, N_("Title")},
    {ID3_FRAME_YEAR, N_("Year")},
    {ID3_FRAME_GENRE, N_("Genre")},
  };

  /* text information */
  for (i = 0; i < sizeof(info) / sizeof(info[0]); ++i) {
    union id3_field const *field;
    unsigned int nstrings, namelen, j;
    char const *name;

    frame = id3_tag_findframe(tag, info[i].id, 0);
    if (frame == 0)
      continue;

    field = &frame->fields[1];
    nstrings = id3_field_getnstrings(field);

    name = info[i].name;
    namelen = name ? strlen(name) : 0;
    //    assert(namelen < sizeof(spaces));

    for (j = 0; j < nstrings; ++j) {
      ucs4 = id3_field_getstrings(field, j);
      assert(ucs4);

      if (strcmp(info[i].id, ID3_FRAME_GENRE) == 0)
	ucs4 = id3_genre_name(ucs4);

      latin1 = id3_ucs4_latin1duplicate(ucs4);
      if (latin1 == 0)
	return;

      if (j == 0 && name) {
	info3->info[PLAYA_INFO_ARTIST+i].s = latin1;
      } else {
	free (latin1);
      }
    }
  }

  /* comments */
  i = 0;
  while ((frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, i++))) {
    id3_latin1_t *ptr;

    ucs4 = id3_field_getstring(&frame->fields[2]);
    assert(ucs4);

    if (*ucs4)
      continue;

    ucs4 = id3_field_getfullstring(&frame->fields[3]);
    assert(ucs4);

    latin1 = id3_ucs4_latin1duplicate(ucs4);
    if (latin1 == 0)
      break;

    {
      int c;
      ptr = latin1;
      while (c=*ptr, c) {
	if (c < ' ' || c>127) *ptr = ' ';
	ptr++;
      }
    }
    if (strlen(latin1) > 0) {
      info3->info[PLAYA_INFO_COMMENTS].s = latin1;
      break; /* One comment only ! */
    } else {
      free (latin1);
    }
  }
}
Beispiel #11
0
static gchar *
getFrameText (struct id3_tag *tag, char *frame_name)
{
  const id3_ucs4_t *string;
  struct id3_frame *frame;
  union id3_field *field;
  gchar *utf8 = NULL;
  enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;

  frame = id3_tag_findframe (tag, frame_name, 0);
  if (!frame)
    return NULL;

  /* Find the encoding used for the field */
  field = id3_frame_field (frame, 0);
  //printf ("field: %p\n", field);
  if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
    {
      encoding = field->number.value;
      //printf ("encoding: %d\n", encoding);
    }

  if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
    field = id3_frame_field (frame, 3);
  else
    field = id3_frame_field (frame, 1);

  //printf ("field: %p\n", field);

  if (!field)
    return NULL;

  if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
    string = id3_field_getfullstring (field);
  else
    string = id3_field_getstrings (field, 0);

  // g_debug("string: %s\n", string);

  if (!string)
    return NULL;

  if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
    string = id3_genre_name (string);

  if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
    {
      /* ISO_8859_1 is just a "marker" -- most people just drop
         whatever coding system they are using into it, so we use
         charset_to_utf8() to convert to utf8 */
      id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
      utf8 = (gchar *) charset_to_utf8 (raw);
      g_free (raw);
    }
  else
    {
      /* Standard unicode is being used -- we won't have to worry
         about charsets then. */
      // g_debug("This frame is a Unicode frame!\n");
      utf8 = (gchar *) id3_ucs4_utf8duplicate (string);
    }
  // g_debug("Found tag: %s, value: %s\n", frame_name, utf8);
  return utf8;
}
Beispiel #12
0
JNIEXPORT jstring JNICALL Java_com_ssb_droidsound_utils_ID3Tag_getStringInfo(JNIEnv *env, jobject obj, jint what)
{
	struct id3_file *id3file = (struct id3_file*)env->GetLongField(obj, refField);
	struct id3_tag *tag = (struct id3_tag*)env->GetLongField(obj, tagRefField);

	__android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "Get String Info %p %p", id3file, tag);


	if(!tag && id3file)
		tag = id3_file_tag(id3file);

	if(!tag) return 0;

	const id3_ucs4_t *title = NULL;
	struct id3_frame *frame = NULL;

	__android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "id3tag %p", tag);

	switch(what) {
	case INFO_TITLE:
		frame = id3_tag_findframe(tag, ID3_FRAME_TITLE, 0);
		break;
	case INFO_AUTHOR:
		frame = id3_tag_findframe(tag, ID3_FRAME_ARTIST, 0);
		break;
	case INFO_COPYRIGHT:
		frame = id3_tag_findframe(tag, ID3_FRAME_YEAR, 0);
		break;
	case ID3INFO_GENRE:
		frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0);
		if(frame) {
			title = id3_field_getstrings(&frame->fields[1], 0);
			title = id3_genre_name(title);
		}
		break;
	case ID3INFO_ALBUM:
		frame = id3_tag_findframe(tag, ID3_FRAME_ALBUM, 0);
		break;
	case ID3INFO_TRACK:
		frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0);
		break;
	case ID3INFO_COMMENT:
		frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, 0);
		if(frame) {
			__android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "COMMENT %d fields", frame->nfields);
			if(frame->nfields >= 4)
				title = id3_field_getfullstring(&frame->fields[3]);
		}
		break;
	}

	if(frame) {

		__android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "frame %p %d", frame, what);

		if(title == NULL)
			title = id3_field_getstrings(&frame->fields[1], 0);
		if(title) {
			__android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "title %p", title);
			id3_utf8_t *titleu8 = id3_ucs4_utf8duplicate(title);
			jstring j = env->NewStringUTF((const char *)titleu8);
			return j;
		}
	}

	return NULL;

}
Beispiel #13
0
static void
getID3Info(struct id3_tag *tag, const char *id, int type, struct tag *mpdTag)
{
	struct id3_frame const *frame;
	id3_ucs4_t const *ucs4;
	id3_utf8_t *utf8;
	union id3_field const *field;
	unsigned int nstrings, i;
	enum id3_field_textencoding id3_encoding = 0xff;

	frame = id3_tag_findframe(tag, id, 0);
	/* Check frame */
	if (!frame)
	{
		return;
	}
	/* Check fields in frame */
	if(frame->nfields == 0)
	{
		g_debug("Frame has no fields");
		return;
	}

	/* Starting with T is a stringlist */
	if (id[0] == 'T')
	{
		/* This one contains 2 fields:
		 * 1st: Text encoding
		 * 2: Stringlist
		 * Shamefully this isn't the RL case.
		 * But I am going to enforce it anyway. 
		 */
		if(frame->nfields != 2) 
		{
			g_debug("Invalid number '%i' of fields for TXX frame",
				frame->nfields);
			return;
		}
		field = &frame->fields[0];
		/**
		 * First field is encoding field.
		 * This is ignored by mpd.
		 */
		if(field->type != ID3_FIELD_TYPE_TEXTENCODING)
		{
			g_debug("Expected encoding, found: %i",
				field->type);
		} else
                        id3_encoding = field->number.value;
		/* Process remaining fields, should be only one */
		field = &frame->fields[1];
		/* Encoding field */
		if(field->type == ID3_FIELD_TYPE_STRINGLIST) {
			/* Get the number of strings available */
			nstrings = id3_field_getnstrings(field);
			for (i = 0; i < nstrings; i++) {
				ucs4 = id3_field_getstrings(field,i);
				if(!ucs4)
					continue;
				utf8 = processID3FieldString(isId3v1(tag),ucs4, type, id3_encoding);
				if(!utf8)
					continue;

				tag_add_item(mpdTag, type, (char *)utf8);
				g_free(utf8);
			}
		}
		else {
			g_warning("Field type not processed: %i",
				  (int)id3_field_gettextencoding(field));
		}
	}
	/* A comment frame */
	else if(!strcmp(ID3_FRAME_COMMENT, id))
	{
		/* A comment frame is different... */
	/* 1st: encoding
         * 2nd: Language
         * 3rd: String
         * 4th: FullString.
         * The 'value' we want is in the 4th field
         */
		if(frame->nfields == 4)
		{
			/* for now I only read the 4th field, with the fullstring */
			field = &frame->fields[3];
			if(field->type == ID3_FIELD_TYPE_STRINGFULL)
			{
				ucs4 = id3_field_getfullstring(field);
				if(ucs4)
				{
					utf8 = processID3FieldString(isId3v1(tag),ucs4, type, id3_encoding);
					if(utf8)
					{
						tag_add_item(mpdTag, type, (char *)utf8);
						g_free(utf8);
					}
				}
			}
			else
			{
				g_debug("4th field in comment frame differs from expected, got '%i': ignoring",
					field->type);
			}
		}
		else
		{
			g_debug("Invalid 'comments' tag, got '%i' fields instead of 4",
				frame->nfields);
		}
	}
	/* Unsupported */
	else
		g_debug("Unsupported tag type requrested");
}
int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
    struct id3_file *pid3file;
    struct id3_tag *pid3tag;
    struct id3_frame *pid3frame;
    int err;
    int index;
    int used;
    char *utf8_text;
    int genre=WINAMP_GENRE_UNKNOWN;
    int have_utf8;
    int have_text;
    id3_ucs4_t const *native_text;
    char *tmp;
    int got_numeric_genre;
    int rating;
    char *conversion_codepage;

    pid3file=id3_file_open(file,ID3_FILE_MODE_READONLY);
    if(!pid3file) {
        DPRINTF(E_WARN,L_SCAN,"Cannot open %s\n",file);
        return FALSE;
    }

    pid3tag=id3_file_tag(pid3file);

    if(!pid3tag) {
        err=errno;
        id3_file_close(pid3file);
        errno=err;
        DPRINTF(E_WARN,L_SCAN,"Cannot get ID3 tag for %s\n",file);
        return FALSE;
    }

    DPRINTF(E_SPAM,L_SCAN,"Starting mp3 tag scan\n");

    conversion_codepage = conf_alloc_string("scanning","mp3_tag_codepage",
                                            "ISO-8859-1");

    index=0;
    while((pid3frame=id3_tag_findframe(pid3tag,"",index))) {
        used=0;
        utf8_text=NULL;
        native_text=NULL;
        have_utf8=0;
        have_text=0;

        DPRINTF(E_SPAM,L_SCAN,"Found tag %s\n",pid3frame->id);

        if(!strcmp(pid3frame->id,"YTCP")) { /* for id3v2.2 */
            pmp3->compilation = 1;
            DPRINTF(E_DBG,L_SCAN,"Compilation: %d\n", pmp3->compilation);
        }

        if(((pid3frame->id[0] == 'T')||(strcmp(pid3frame->id,"COMM")==0)) &&
           (id3_field_getnstrings(&pid3frame->fields[1])))
            have_text=1;

        if(have_text) {
            native_text=id3_field_getstrings(&pid3frame->fields[1],0);

            if(native_text) {
                have_utf8=1;


                utf8_text = (char*)id3_ucs4_utf8duplicate(native_text);
                if(utf8_text)
                    mem_register(utf8_text,0);

                if(id3_field_gettextencoding(&pid3frame->fields[1]) ==
                   ID3_FIELD_TEXTENCODING_ISO_8859_1) {
#ifdef HAVE_ICONV
                    /* this is kinda cheesy, but ucs4* == char* for 8859-1 */
                    free(utf8_text);
                    utf8_text =
                        (char*)util_xtoutf8_alloc((unsigned char*)native_text,
                                                  strlen((char*)native_text),
                                                  conversion_codepage);
#endif
                }



                if(!strcmp(pid3frame->id,"TIT2")) { /* Title */
                    used=1;
                    pmp3->title = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Title: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TPE1")) {
                    used=1;
                    pmp3->artist = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Artist: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TALB")) {
                    used=1;
                    pmp3->album = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Album: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TCOM")) {
                    used=1;
                    pmp3->composer = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Composer: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TIT1")) {
                    used=1;
                    pmp3->grouping = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Grouping: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TPE2")) {
                    used=1;
                    pmp3->orchestra = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Orchestra: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TPE3")) {
                    used=1;
                    pmp3->conductor = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Conductor: %s\n",utf8_text);
                } else if(!strcmp(pid3frame->id,"TCON")) {
                    used=1;
                    pmp3->genre = utf8_text;
                    got_numeric_genre=0;
                    DPRINTF(E_DBG,L_SCAN," Genre: %s\n",utf8_text);
                    if(pmp3->genre) {
                        if(!strlen(pmp3->genre)) {
                            genre=WINAMP_GENRE_UNKNOWN;
                            got_numeric_genre=1;
                        } else if (scan_mp3_is_numeric(pmp3->genre)) {
                            genre=atoi(pmp3->genre);
                            got_numeric_genre=1;
                        } else if ((pmp3->genre[0] == '(') && (isdigit(pmp3->genre[1]))) {
                            genre=atoi((char*)&pmp3->genre[1]);
                            got_numeric_genre=1;
                        }

                        if(got_numeric_genre) {
                            if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
                                genre=WINAMP_GENRE_UNKNOWN;
                            free(pmp3->genre);
                            pmp3->genre=strdup(scan_winamp_genre[genre]);
                        }
                    }
                } else if(!strcmp(pid3frame->id,"COMM")) {
                    used=1;
                    pmp3->comment = utf8_text;
                    DPRINTF(E_DBG,L_SCAN," Comment: %s\n",pmp3->comment);
                } else if(!strcmp(pid3frame->id,"TPOS")) {
                    tmp=utf8_text;
                    strsep(&tmp,"/");
                    if(tmp) {
                        pmp3->total_discs=atoi(tmp);
                    }
                    pmp3->disc=atoi(utf8_text);
                    DPRINTF(E_DBG,L_SCAN," Disc %d of %d\n",pmp3->disc,pmp3->total_discs);
                } else if(!strcmp(pid3frame->id,"TRCK")) {
                    tmp=utf8_text;
                    strsep(&tmp,"/");
                    if(tmp) {
                        pmp3->total_tracks=atoi(tmp);
                    }
                    pmp3->track=atoi(utf8_text);
                    DPRINTF(E_DBG,L_SCAN," Track %d of %d\n",pmp3->track,pmp3->total_tracks);
                } else if(!strcmp(pid3frame->id,"TDRC")) {
                    pmp3->year = atoi(utf8_text);
                    DPRINTF(E_DBG,L_SCAN," Year: %d\n",pmp3->year);
                } else if(!strcmp(pid3frame->id,"TLEN")) {
                    pmp3->song_length = atoi(utf8_text); /* now in ms */
                    DPRINTF(E_DBG,L_SCAN," Length: %d\n", pmp3->song_length);
                } else if(!strcmp(pid3frame->id,"TBPM")) {
                    pmp3->bpm = atoi(utf8_text);
                    DPRINTF(E_DBG,L_SCAN,"BPM: %d\n", pmp3->bpm);
                } else if(!strcmp(pid3frame->id,"TCMP")) { /* for id3v2.3 */
                    pmp3->compilation = (char)atoi(utf8_text);
                    DPRINTF(E_DBG,L_SCAN,"Compilation: %d\n", pmp3->compilation);
                }
            }
        }

        /* can check for non-text tags here */
        if((!used) && (have_utf8) && (utf8_text))
            free(utf8_text);

        if((!strcmp(pid3frame->id,"POPM")) && (pid3frame->nfields == 3)) {
            rating = id3_field_getint(&pid3frame->fields[1]);
            if(rating >= 0x01)
                pmp3->rating = 20;
            if(rating >= 0x40)
                pmp3->rating = 40;
            if(rating >= 0x80)
                pmp3->rating = 60;
            if(rating >= 0xC4)
                pmp3->rating = 80;
            if(rating >= 0xFF)
                pmp3->rating = 100;
        }


        /* v2 COMM tags are a bit different than v1 */
        if((!strcmp(pid3frame->id,"COMM")) && (pid3frame->nfields == 4)) {
            /* Make sure it isn't a application-specific comment...
             * This currently includes the following:
             *
             * iTunes_CDDB_IDs
             * iTunNORM
             *
             * If other apps stuff crap into comment fields, then we'll ignore them
             * here.
             */
            native_text=id3_field_getstring(&pid3frame->fields[2]);
            if(native_text) {
                utf8_text=(char*)id3_ucs4_utf8duplicate(native_text);
                if(utf8_text)
                    mem_register(utf8_text,0);

                if((utf8_text) && (strncasecmp(utf8_text,"iTun",4) != 0)) {
                    /* it's a real comment */
                    if(utf8_text)
                        free(utf8_text);

                    native_text=id3_field_getfullstring(&pid3frame->fields[3]);
                    if(native_text) {
                        if(pmp3->comment)
                            free(pmp3->comment);
                        utf8_text=(char*)id3_ucs4_utf8duplicate(native_text);
                        if(utf8_text) {
                            mem_register(utf8_text,0);
                            pmp3->comment=utf8_text;
                        }
                    }
                } else {
                    if(utf8_text)
                        free(utf8_text);
                }
            }
        }

        index++;
    }

    free(conversion_codepage);
    id3_file_close(pid3file);
    DPRINTF(E_DBG,L_SCAN,"Got id3 tag successfully\n");
    return TRUE;
}
Beispiel #15
0
void MP3ImportFileHandle::ImportID3(Tags *tags)
{
#ifdef USE_LIBID3TAG
   wxFile f;   // will be closed when it goes out of scope
   struct id3_file *fp = NULL;

   if (f.Open(mFilename)) {
      // Use id3_file_fdopen() instead of id3_file_open since wxWidgets can open a
      // file with a Unicode name and id3_file_open() can't (under Windows).
      fp = id3_file_fdopen(f.fd(), ID3_FILE_MODE_READONLY);
   }

   if (!fp) {
      return;
   }

   // The file descriptor is now owned by "fp", so we must tell "f" to forget
   // about it.
   f.Detach();

   struct id3_tag *tp = id3_file_tag(fp);
   if (!tp) {
      id3_file_close(fp);
      return;
   }

   tags->Clear();

   // Loop through all frames
   bool have_year = false;
   for (int i = 0; i < (int) tp->nframes; i++) {
      struct id3_frame *frame = tp->frames[i];

      // printf("ID: %08x '%4s'\n", (int) *(int *)frame->id, frame->id);
      // printf("Desc: %s\n", frame->description);
      // printf("Num fields: %d\n", frame->nfields);

      // for (int j = 0; j < (int) frame->nfields; j++) {
      //    printf("field %d type %d\n", j, frame->fields[j].type );
      //    if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST) {
      //       printf("num strings %d\n", frame->fields[j].stringlist.nstrings);
      //    }
      // }

      wxString n, v;

      // Determine the tag name
      if (strcmp(frame->id, ID3_FRAME_TITLE) == 0) {
         n = TAG_TITLE;
      }
      else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0) {
         n = TAG_ARTIST;
      }
      else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0) {
         n = TAG_ALBUM;
      }
      else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0) {
         n = TAG_TRACK;
      }
      else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0) {
         // LLL:  When libid3tag encounters the "TYER" tag, it converts it to a
         //       "ZOBS" (obsolete) tag and adds a "TDRC" tag at the end of the
         //       list of tags using the first 4 characters of the "TYER" tag.
         //       Since we write both the "TDRC" and "TYER" tags, the "TDRC" tag
         //       will always be encountered first in the list.  We want use it
         //       since the converted "TYER" tag may have been truncated.
         if (have_year) {
            continue;
         }
         n = TAG_YEAR;
         have_year = true;
      }
      else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0) {
         n = TAG_COMMENTS;
      }
      else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0) {
         n = TAG_GENRE;
      }
   else {
         // Use frame description as default tag name.  The descriptions
         // may include several "meanings" separated by "/" characters, so
         // we just use the first meaning
         n = UTF8CTOWX(frame->description).BeforeFirst(wxT('/'));
      }

      const id3_ucs4_t *ustr = NULL;

      if (n == TAG_COMMENTS) {
         ustr = id3_field_getfullstring(&frame->fields[3]);
      }
      else if (frame->nfields == 3) {
         ustr = id3_field_getstring(&frame->fields[1]);
         if (ustr) {
            char *str = (char *)id3_ucs4_utf8duplicate(ustr);
            n = UTF8CTOWX(str);
            free(str);
         }

         ustr = id3_field_getstring(&frame->fields[2]);
      }
      else if (frame->nfields >= 2) {
         ustr = id3_field_getstrings(&frame->fields[1], 0);
      }

      if (ustr) {
         char *str = (char *)id3_ucs4_utf8duplicate(ustr);
         v = UTF8CTOWX(str);
         free(str);
      }

      if (!n.IsEmpty() && !v.IsEmpty()) {
         tags->SetTag(n, v);
   }
}

   // Convert v1 genre to name
   if (tags->HasTag(TAG_GENRE)) {
      long g = -1;
      if (tags->GetTag(TAG_GENRE).ToLong(&g)) {
         tags->SetTag(TAG_GENRE, tags->GetGenre(g));
   }
}

   id3_file_close(fp);
#endif // ifdef USE_LIBID3TAG
}
Beispiel #16
0
/* stolen from mpg321
 *
 * Convenience for retrieving already formatted id3 data
 * what parameter is one of
 *  ID3_FRAME_TITLE
 *  ID3_FRAME_ARTIST
 *  ID3_FRAME_ALBUM
 *  ID3_FRAME_YEAR
 *  ID3_FRAME_COMMENT
 *  ID3_FRAME_GENRE
 */
string LibMadWrapper::id3_get_tag(struct id3_tag const *tag, char const *what)
{
    struct id3_frame const *frame = NULL;
    union id3_field const *field = NULL;
    int nstrings;
    int avail;
    int j;
    int tocopy;
    int len;
    char printable[1024];
    id3_ucs4_t const *ucs4 = NULL;
    id3_latin1_t *latin1 = NULL;

    memset(printable, '\0', 1024);
    avail = 1024;
    if (strcmp(what, ID3_FRAME_COMMENT) == 0)
    {
        /*There may be sth wrong. I did not fully understand how to use
            libid3tag for retrieving comments  */
        j = 0;
        frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, j++);
        if (!frame)
        {
            return "";
        }
        ucs4 = id3_field_getfullstring(&frame->fields[3]);
        if (!ucs4)
        {
            return "";
        }
        latin1 = id3_ucs4_latin1duplicate(ucs4);
        if (!latin1 || strlen(reinterpret_cast<char *>(latin1)) == 0)
        {
            return "";
        }
        len = strlen(reinterpret_cast<char *>(latin1));
        if (avail > len)
        {
            tocopy = len;
        }
        else
        {
            tocopy = 0;
        }
        if (!tocopy)
        {
            return "";
        }
        avail -= tocopy;
        strncat(printable, reinterpret_cast<char *>(latin1), tocopy);
        free(latin1);
    }

    else
    {
        frame = id3_tag_findframe(tag, what, 0);
        if (!frame)
        {
            return "";
        }
        field = &frame->fields[1];
        nstrings = id3_field_getnstrings(field);
        for (j = 0; j < nstrings; ++j)
        {
            ucs4 = id3_field_getstrings(field, j);
            if (!ucs4)
            {
                return "";
            }
            if (strcmp(what, ID3_FRAME_GENRE) == 0)
            {
                ucs4 = id3_genre_name(ucs4);
            }
            latin1 = id3_ucs4_latin1duplicate(ucs4);
            if (!latin1)
            {
                break;
            }
            len = strlen(reinterpret_cast<char *>(latin1));
            if (avail > len)
            {
                tocopy = len;
            }
            else
            {
                tocopy = 0;
            }
            if (!tocopy)
            {
                break;
            }
            avail -= tocopy;
            strncat(printable, reinterpret_cast<char *>(latin1), tocopy);
            free(latin1);
        }
    }

    return string(printable);
}
Beispiel #17
0
static int
_get_mp3tags(char *file, struct song_metadata *psong)
{
	struct id3_file *pid3file;
	struct id3_tag *pid3tag;
	struct id3_frame *pid3frame;
	int err;
	int index;
	int used;
	unsigned char *utf8_text;
	int genre = WINAMP_GENRE_UNKNOWN;
	int have_utf8;
	int have_text;
	id3_ucs4_t const *native_text;
	char *tmp;
	int got_numeric_genre;
	id3_byte_t const *image;
	id3_length_t image_size = 0;

	pid3file = id3_file_open(file, ID3_FILE_MODE_READONLY);
	if(!pid3file)
	{
		DPRINTF(E_ERROR, L_SCANNER, "Cannot open %s\n", file);
		return -1;
	}

	pid3tag = id3_file_tag(pid3file);

	if(!pid3tag)
	{
		err = errno;
		id3_file_close(pid3file);
		errno = err;
		DPRINTF(E_WARN, L_SCANNER, "Cannot get ID3 tag for %s\n", file);
		return -1;
	}

	index = 0;
	while((pid3frame = id3_tag_findframe(pid3tag, "", index)))
	{
		used = 0;
		utf8_text = NULL;
		native_text = NULL;
		have_utf8 = 0;
		have_text = 0;

		if(!strcmp(pid3frame->id, "YTCP"))   /* for id3v2.2 */
		{
			psong->compilation = 1;
			DPRINTF(E_DEBUG, L_SCANNER, "Compilation: %d [%s]\n", psong->compilation, basename(file));
		}
		else if(!strcmp(pid3frame->id, "APIC") && !image_size)
		{
			if( (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpeg") == 0) ||
			    (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpg") == 0) ||
			    (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "jpeg") == 0)
#if HAVE_LIBPNG
			    || (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/png") == 0) ||
				(strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "png") == 0)
#endif
			)
			{
				image = id3_field_getbinarydata(&pid3frame->fields[4], &image_size);
				if( image_size )
				{
					psong->image = malloc(image_size);
					memcpy(psong->image, image, image_size);
					psong->image_size = image_size;
					//DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size);
				}
			}
		}

		if(((pid3frame->id[0] == 'T') || (strcmp(pid3frame->id, "COMM") == 0)) &&
		   (id3_field_getnstrings(&pid3frame->fields[1])))
			have_text = 1;

		if(have_text)
		{
			native_text = id3_field_getstrings(&pid3frame->fields[1], 0);

			if(native_text)
			{
				have_utf8 = 1;
				if(lang_index >= 0)
					utf8_text = _get_utf8_text(native_text); // through iconv
				else
					utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);

				if(!strcmp(pid3frame->id, "TIT2"))
				{
					used = 1;
					psong->title = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPE1"))
				{
					used = 1;
					psong->contributor[ROLE_ARTIST] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TALB"))
				{
					used = 1;
					psong->album = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TCOM"))
				{
					used = 1;
					psong->contributor[ROLE_COMPOSER] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TIT1"))
				{
					used = 1;
					psong->grouping = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPE2"))
				{
					used = 1;
					psong->contributor[ROLE_BAND] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPE3"))
				{
					used = 1;
					psong->contributor[ROLE_CONDUCTOR] = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TCON"))
				{
					used = 1;
					psong->genre = (char*)utf8_text;
					got_numeric_genre = 0;
					if(psong->genre)
					{
						if(!strlen(psong->genre))
						{
							genre = WINAMP_GENRE_UNKNOWN;
							got_numeric_genre = 1;
						}
						else if(isdigit(psong->genre[0]))
						{
							genre = atoi(psong->genre);
							got_numeric_genre = 1;
						}
						else if((psong->genre[0] == '(') && (isdigit(psong->genre[1])))
						{
							genre = atoi((char*)&psong->genre[1]);
							got_numeric_genre = 1;
						}

						if(got_numeric_genre)
						{
							if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
								genre = WINAMP_GENRE_UNKNOWN;
							free(psong->genre);
							psong->genre = strdup(winamp_genre[genre]);
						}
					}
				}
				else if(!strcmp(pid3frame->id, "COMM"))
				{
					used = 1;
					psong->comment = (char*)utf8_text;
				}
				else if(!strcmp(pid3frame->id, "TPOS"))
				{
					tmp = (char*)utf8_text;
					strsep(&tmp, "/");
					if(tmp)
					{
						psong->total_discs = atoi(tmp);
					}
					psong->disc = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TRCK"))
				{
					tmp = (char*)utf8_text;
					strsep(&tmp, "/");
					if(tmp)
					{
						psong->total_tracks = atoi(tmp);
					}
					psong->track = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TDRC"))
				{
					psong->year = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TLEN"))
				{
					psong->song_length = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TBPM"))
				{
					psong->bpm = atoi((char*)utf8_text);
				}
				else if(!strcmp(pid3frame->id, "TCMP"))
				{
					psong->compilation = (char)atoi((char*)utf8_text);
				}
			}
		}

		// check if text tag
		if((!used) && (have_utf8) && (utf8_text))
			free(utf8_text);

		// v2 COMM
		if((!strcmp(pid3frame->id, "COMM")) && (pid3frame->nfields == 4))
		{
			native_text = id3_field_getstring(&pid3frame->fields[2]);
			if(native_text)
			{
				utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
				if((utf8_text) && (strncasecmp((char*)utf8_text, "iTun", 4) != 0))
				{
					// read comment
					free(utf8_text);

					native_text = id3_field_getfullstring(&pid3frame->fields[3]);
					if(native_text)
					{
						utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
						if(utf8_text)
						{
							free(psong->comment);
							psong->comment = (char*)utf8_text;
						}
					}
				}
				else
				{
					free(utf8_text);
				}
			}
		}

		index++;
	}

	id3_file_close(pid3file);
	//DEBUG DPRINTF(E_INFO, L_SCANNER, "Got id3 tag successfully for file=%s\n", file);
	return 0;
}