id3_byte_t const* id3_metadata_getuniquefileidentifier(const struct id3_tag* tag, const char* owner_identifier, id3_length_t* length) { int i=0, result; id3_ucs4_t const * ucs4; id3_latin1_t* latin1; union id3_field const *field; struct id3_frame const *frame; id3_byte_t const* identifier; for (i=0; ; ++i) { frame = id3_tag_findframe(tag, "UFID", i); if (frame == 0) return 0; field = id3_frame_field(frame, 0); if (field == 0) return 0; if (strcmp(id3_field_getlatin1(field), owner_identifier)==0) break; } field = id3_frame_field(frame, 1); if (field == 0) return 0; return id3_field_getbinarydata(field, length); }
/** * Imports the MusicBrainz TrackId from the UFID tag. */ static void tag_id3_import_ufid(struct tag *mpd_tag, struct id3_tag *id3_tag) { for (unsigned i = 0;; ++i) { const struct id3_frame *frame; union id3_field *field; const id3_latin1_t *name; const id3_byte_t *value; id3_length_t length; frame = id3_tag_findframe(id3_tag, "UFID", i); if (frame == NULL) break; field = id3_frame_field(frame, 0); if (field == NULL) continue; name = id3_field_getlatin1(field); if (name == NULL || strcmp((const char *)name, "http://musicbrainz.org") != 0) continue; field = id3_frame_field(frame, 1); if (field == NULL) continue; value = id3_field_getbinarydata(field, &length); if (value == NULL || length == 0) continue; tag_add_item_n(mpd_tag, TAG_MUSICBRAINZ_TRACKID, (const char*)value, length); } }
static int extract_pic(struct id3_frame *frame, int dest) { union id3_field *field; unsigned char const *data; id3_length_t length; int done = 0; field = id3_frame_field(frame, 4); data = id3_field_getbinarydata(field, &length); if (!data) { fprintf(stderr, "No image data found for frame\n"); return 0; } while (length > 0) { ssize_t res; if ((res = write(dest, data + done, length)) < 0) { if (errno == EINTR) continue; perror("Unable to write to file"); return 0; } length -= res; done += res; } return 1; }
id3_byte_t const* id3_metadata_getpicturedata(const struct id3_tag* tag, enum id3_picture_type picture_type, id3_length_t* length) { union id3_field const *field; struct id3_frame const *frame; frame=id3_metadata_getpictureframebytype(tag, picture_type); if (frame==0) return 0; field = id3_frame_field(frame, 4); if (field == 0) return 0; return id3_field_getbinarydata(field, length); }
/* Parse mp3 RVA2 frame. Shamelessly stolen from madplay. */ static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gain_info) { struct id3_frame const * frame; id3_latin1_t const *id; id3_byte_t const *data; id3_length_t length; int found; enum { CHANNEL_OTHER = 0x00, CHANNEL_MASTER_VOLUME = 0x01, CHANNEL_FRONT_RIGHT = 0x02, CHANNEL_FRONT_LEFT = 0x03, CHANNEL_BACK_RIGHT = 0x04, CHANNEL_BACK_LEFT = 0x05, CHANNEL_FRONT_CENTRE = 0x06, CHANNEL_BACK_CENTRE = 0x07, CHANNEL_SUBWOOFER = 0x08 }; found = 0; /* relative volume adjustment information */ frame = id3_tag_findframe(tag, "RVA2", 0); if (!frame) return 0; id = id3_field_getlatin1(id3_frame_field(frame, 0)); data = id3_field_getbinarydata(id3_frame_field(frame, 1), &length); if (!id || !data) return 0; /* * "The 'identification' string is used to identify the * situation and/or device where this adjustment should apply. * The following is then repeated for every channel * * Type of channel $xx * Volume adjustment $xx xx * Bits representing peak $xx * Peak volume $xx (xx ...)" */ while (length >= 4) { unsigned int peak_bytes; peak_bytes = (data[3] + 7) / 8; if (4 + peak_bytes > length) break; if (data[0] == CHANNEL_MASTER_VOLUME) { signed int voladj_fixed; double voladj_float; /* * "The volume adjustment is encoded as a fixed * point decibel value, 16 bit signed integer * representing (adjustment*512), giving +/- 64 * dB with a precision of 0.001953125 dB." */ voladj_fixed = (data[1] << 8) | (data[2] << 0); voladj_fixed |= -(voladj_fixed & 0x8000); voladj_float = (double) voladj_fixed / 512; replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = voladj_float; replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = voladj_float; g_debug("parseRVA2: Relative Volume " "%+.1f dB adjustment (%s)\n", voladj_float, id); found = 1; break; } data += 4 + peak_bytes; length -= 4 + peak_bytes; } return found; }
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; }
char load(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity, char immediate_load) { ImlibLoader *loader; lopt opt; int res; struct stat st; assert(im); if (stat(im->real_file, &st) < 0) return 0; if (!get_options(&opt, im)) return 0; if (!get_loader(&opt, &loader)) goto fail_context; if (loader) { char *ofile, tmp[] = "/tmp/imlib2_loader_id3-XXXXXX"; int dest; if ((dest = mkstemp(tmp)) < 0) { fprintf(stderr, "Unable to create a temporary file\n"); goto fail_context; } res = extract_pic(id3_tag_get_frame(opt.ctx->tag, opt.index - 1), dest); close(dest); if (!res) { unlink(tmp); goto fail_context; } ofile = im->real_file; im->real_file = strdup(tmp); res = loader->load(im, progress, progress_granularity, immediate_load); free(im->real_file); im->real_file = ofile; unlink(tmp); } else { /* The tag actually provides a image url rather than image data. * Practically, dunno if such a tag exists on earth :) * Here's the code anyway... */ union id3_field *field; id3_length_t length; char const *data; char *url, *file, *ofile; field = id3_frame_field (id3_tag_get_frame(opt.ctx->tag, opt.index - 1), 4); data = (char const *)id3_field_getbinarydata(field, &length); if (!data || !length) { fprintf(stderr, "No link image URL present\n"); goto fail_context; } url = (char *)malloc((length + 1) * sizeof(char)); strncpy(url, data, length); url[length] = '\0'; file = (strncmp(url, "file://", 7) ? url : url + 7); if (!(loader = __imlib_FindBestLoaderForFile(file, 0))) { fprintf(stderr, "No loader found for file %s\n", file); free(url); goto fail_context; } ofile = im->real_file; im->real_file = file; res = loader->load(im, progress, progress_granularity, immediate_load); if (!im->loader) __imlib_AttachTag(im, "id3-link-url", 0, url, destructor_data); else free(url); im->real_file = ofile; } if (!im->loader) write_tags(im, &opt); #ifdef DEBUG if (!im->loader) { ImlibImageTag *cur = im->tags; fprintf(stderr, "Tags for file %s:\n", im->file); while (cur) { fprintf(stderr, "\t%s: (%d) %s\n", cur->key, cur->val, (char *)cur->data); cur = cur->next; } } #endif context_delref(opt.ctx); return res; fail_context: context_delref(opt.ctx); return 0; }
/***************************************************************************** * ParseID3Tag : parse an id3tag into the info structures *****************************************************************************/ static void ParseID3Tag( demux_meta_t *p_demux_meta, const uint8_t *p_data, int i_size ) { struct id3_tag *p_id3_tag; struct id3_frame *p_frame; vlc_meta_t *p_meta; int i; p_id3_tag = id3_tag_parse( p_data, i_size ); if( !p_id3_tag ) return; if( !p_demux_meta->p_meta ) p_demux_meta->p_meta = vlc_meta_New(); p_meta = p_demux_meta->p_meta; #define ID_IS( a ) (!strcmp( p_frame->id, a )) #define DESCR_IS( a) strstr( (char*)p_frame->description, a ) #define GET_STRING(frame,fidx) id3_ucs4_latin1duplicate( id3_field_getstring( &(frame)->fields[fidx] ) ) /* */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "UFID", i )) != NULL; i++ ) { const char *psz_owner = id3_field_getlatin1( &p_frame->fields[0] ); if( !strncmp( psz_owner, "http://musicbrainz.org", 22 ) ) { id3_byte_t const * p_ufid; id3_length_t i_ufidlen; p_ufid = id3_field_getbinarydata( &p_frame->fields[1], &i_ufidlen ); char *psz_ufid = strndup( p_ufid, i_ufidlen ); vlc_meta_SetTrackID( p_meta, psz_ufid ); free( psz_ufid ); } } /* User defined text (TXXX) */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "TXXX", i )) != NULL; i++ ) { /* 3 fields: 'encoding', 'description', 'value' */ char *psz_name = GET_STRING( p_frame, 1 ); char *psz_value = GET_STRING( p_frame, 2 ); vlc_meta_AddExtra( p_meta, psz_name, psz_value ); #if 0 if( !strncmp( psz_name, "MusicBrainz Artist Id", 21 ) ) vlc_meta_SetArtistID( p_meta, psz_value ); if( !strncmp( psz_desc, "MusicBrainz Album Id", 20 ) ) vlc_meta_SetAlbumID( p_meta, psz_value ); #endif free( psz_name ); free( psz_value ); } /* Relative volume adjustment */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "RVA2", i )) != NULL; i++ ) { /* 2 fields: 'latin1', 'binary' */ const char *psz_type = id3_field_getlatin1( &p_frame->fields[0] ); if( !strcasecmp( psz_type, "track" ) || !strcasecmp( psz_type, "album" ) || !strcasecmp( psz_type, "normalize" ) ) { id3_byte_t const * p_data; id3_length_t i_data; p_data = id3_field_getbinarydata( &p_frame->fields[1], &i_data ); while( i_data >= 4 ) { const unsigned int i_peak_size = p_data[3]; const float f_temp = GetWBE( &p_data[1] ); const float f_gain = f_temp / 512.0; char psz_value[32]; if( i_data < i_peak_size + 4 ) break; /* only master volume */ if( p_data[0] == 0x01 ) { snprintf( psz_value, sizeof(psz_value), "%f", f_gain ); if( !strcasecmp( psz_type, "album" ) ) vlc_meta_AddExtra( p_meta, "REPLAYGAIN_ALBUM_GAIN", psz_value ); else vlc_meta_AddExtra( p_meta, "REPLAYGAIN_TRACK_GAIN", psz_value ); /* XXX I have no idea what peak unit is ... */ } i_data -= 4+i_peak_size; } } } /* TODO 'RGAD' if it is used somewhere */ /* T--- Text informations */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "T", i )) != NULL; i++ ) { unsigned i_strings; /* Special case TXXX is not the same beast */ if( ID_IS( "TXXX" ) ) continue; i_strings = id3_field_getnstrings( &p_frame->fields[1] ); while( i_strings > 0 ) { char *psz_temp = id3_ucs4_utf8duplicate( id3_field_getstrings( &p_frame->fields[1], --i_strings ) ); if( ID_IS( ID3_FRAME_GENRE ) ) { char *psz_endptr; int i_genre = strtol( psz_temp, &psz_endptr, 10 ); if( psz_temp != psz_endptr && i_genre >= 0 && i_genre < NUM_GENRES ) { vlc_meta_SetGenre( p_meta, ppsz_genres[atoi(psz_temp)]); } else { /* Unknown genre */ vlc_meta_SetGenre( p_meta,psz_temp ); } } else if( ID_IS( ID3_FRAME_TITLE ) ) { vlc_meta_SetTitle( p_meta, psz_temp ); } else if( ID_IS( ID3_FRAME_ARTIST ) ) { vlc_meta_SetArtist( p_meta, psz_temp ); } else if( ID_IS( ID3_FRAME_YEAR ) ) { vlc_meta_SetDate( p_meta, psz_temp ); } else if( ID_IS( ID3_FRAME_COMMENT ) ) { vlc_meta_SetDescription( p_meta, psz_temp ); } else if( DESCR_IS( "Copyright" ) ) { vlc_meta_SetCopyright( p_meta, psz_temp ); } else if( DESCR_IS( "Publisher" ) ) { vlc_meta_SetPublisher( p_meta, psz_temp ); } else if( DESCR_IS( "Track number/position in set" ) ) { vlc_meta_SetTrackNum( p_meta, psz_temp ); } else if( DESCR_IS( "Album/movie/show title" ) ) { vlc_meta_SetAlbum( p_meta, psz_temp ); } else if( DESCR_IS( "Encoded by" ) ) { vlc_meta_SetEncodedBy( p_meta, psz_temp ); } else if( ID_IS ( "APIC" ) ) { msg_Dbg( p_demux_meta, "** Has APIC **" ); } else if( p_frame->description ) { /* Unhandled meta */ vlc_meta_AddExtra( p_meta, (char*)p_frame->description, psz_temp ); } free( psz_temp ); } } id3_tag_delete( p_id3_tag ); #undef GET_STRING #undef DESCR_IS #undef ID_IS }
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; }
/* * NAME: compat->fixup() * DESCRIPTION: finish compatibility translations */ int id3_compat_fixup(struct id3_tag *tag) { struct id3_frame *frame; unsigned int index; id3_ucs4_t timestamp[17] = { 0 }; int result = 0; /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ /* * TYE/TYER: YYYY * TDA/TDAT: DDMM * TIM/TIME: HHMM * * TDRC: yyyy-MM-ddTHH:mm */ index = 0; while((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { char const *id; id3_byte_t const *data, *end; id3_length_t length; enum id3_field_textencoding encoding; id3_ucs4_t *string; id = id3_field_getframeid(&frame->fields[0]); assert(id); if(strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) continue; data = id3_field_getbinarydata(&frame->fields[1], &length); assert(data); if(length < 1) continue; end = data + length; encoding = (enum id3_field_textencoding)id3_parse_uint(&data, 1); string = id3_parse_string(&data, end - data, encoding, 0); if(id3_ucs4_length(string) < 4) { free(string); continue; } if(strcmp(id, "TYER") == 0 || strcmp(id, "YTYE") == 0) { timestamp[0] = string[0]; timestamp[1] = string[1]; timestamp[2] = string[2]; timestamp[3] = string[3]; } else if(strcmp(id, "TDAT") == 0 || strcmp(id, "YTDA") == 0) { timestamp[4] = '-'; timestamp[5] = string[2]; timestamp[6] = string[3]; timestamp[7] = '-'; timestamp[8] = string[0]; timestamp[9] = string[1]; } else /* TIME or YTIM */ { timestamp[10] = 'T'; timestamp[11] = string[0]; timestamp[12] = string[1]; timestamp[13] = ':'; timestamp[14] = string[2]; timestamp[15] = string[3]; } free(string); } if(timestamp[0]) { id3_ucs4_t *strings; frame = id3_frame_new("TDRC"); if(frame == 0) goto fail; strings = timestamp; if(id3_field_settextencoding(&frame->fields[0], ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || id3_tag_attachframe(tag, frame) == -1) { id3_frame_delete(frame); goto fail; } } if(0) { fail: result = -1; } return result; }