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 }
/* * 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); } } }
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; }