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