From 56ed6fb018b33a7f887e599ac0dccd3b6ebe44ca Mon Sep 17 00:00:00 2001 From: thor Date: Sat, 1 Dec 2007 21:42:44 +0000 Subject: [PATCH] Some things relating to ID3v2 handling: - the named entries for artist, album, etc in struct mpg123_id3v2 are now pointers... - ... into the new arrays of ID3v2 text, comment and extra (TXXX) data - That makes a lot more info directly accessible; which id3dump now does access - adapted id3print.c to the pointer thing (by dropping some & ;-) - mpg123_copy_string() now produces an empty string (_not_ "") when copying from NULL id3.c got a bit of structure, but the main parsing function is still to bloated. In general, I hope this change of ID3v2 handling makes sense. You have more data plus the possibility to easily loop through the entries... git-svn-id: svn://scm.orgis.org/mpg123/trunk@1205 35dc7657-300d-0410-a2e5-dc2837fedb53 --- doc/examples/id3dump.c | 59 +++++++-- src/id3print.c | 12 +- src/libmpg123/id3.c | 265 +++++++++++++++++++++++--------------- src/libmpg123/id3.h | 1 + src/libmpg123/libmpg123.c | 1 + src/libmpg123/mpg123.h.in | 32 +++-- src/libmpg123/stringbuf.c | 21 ++- 7 files changed, 255 insertions(+), 136 deletions(-) diff --git a/doc/examples/id3dump.c b/doc/examples/id3dump.c index 49ac7100..194cb9ce 100644 --- a/doc/examples/id3dump.c +++ b/doc/examples/id3dump.c @@ -87,18 +87,56 @@ void print_v2(mpg123_id3v2 *v2) int i; const char *names[] = { "Title", "Artist", "Album", "Year", "Comment", "Genre" }; mpg123_string *sources[sizeof(names)/sizeof(char*)]; - sources[0] = &v2->title; - sources[1] = &v2->artist; - sources[2] = &v2->album; - sources[3] = &v2->year; - sources[4] = v2->generic_comment; - sources[5] = &v2->genre; + sources[0] = v2->title; + sources[1] = v2->artist; + sources[2] = v2->album; + sources[3] = v2->year; + sources[4] = v2->comment; + sources[5] = v2->genre; + printf("title = %p\n", (void*)v2->title); for(i=0; itexts; ++i) + { + char id[5]; + memcpy(id, v2->text[i].id, 4); + id[4] = 0; + printf("%p %s\n", (void*)(&v2->text[i].text), id); + print_lines("", &v2->text[i].text); + } + for(i=0; iextras; ++i) + { + char id[5]; + memcpy(id, v2->extra[i].id, 4); + id[4] = 0; + printf( "%s description(%s)\n", + id, + v2->extra[i].description.fill ? v2->extra[i].description.p : "" ); + print_lines("", &v2->extra[i].text); + } + for(i=0; icomments; ++i) + { + char id[5]; + char lang[3]; + memcpy(id, v2->comment_list[i].id, 4); + id[4] = 0; + memcpy(lang, v2->comment_list[i].lang, 3); + lang[3] = 0; + printf( "%s description(%s) language(%s): \n", + id, + v2->comment_list[i].description.fill ? v2->comment_list[i].description.p : "", + lang ); + print_lines("", &v2->comment_list[i].text); + } +} + int main(int argc, char **argv) { int i; @@ -112,7 +150,7 @@ int main(int argc, char **argv) mpg123_init(); m = mpg123_new(NULL, NULL); mpg123_param(m, MPG123_VERBOSE, 4, 0); - + for(i=1; i < argc; ++i) { mpg123_id3v1 *v1; @@ -128,11 +166,14 @@ mpg123_param(m, MPG123_VERBOSE, 4, 0); if(meta & MPG123_ID3 && mpg123_id3(m, &v1, &v2) == MPG123_OK) { printf("Tag data on %s:\n", argv[i]); - printf("\n==== ID3v1 ====\n"); + printf("\n==== ID3v1 ====\n"); if(v1 != NULL) print_v1(v1); - printf("\n==== ID3v2 ====\n"); + printf("\n==== ID3v2 ====\n"); if(v2 != NULL) print_v2(v2); + + printf("\n==== ID3v2 Raw frames ====\n"); + if(v2 != NULL) print_raw_v2(v2); } else printf("Nothing found for %s.\n", argv[i]); diff --git a/src/id3print.c b/src/id3print.c index b7786f84..e100e2d4 100644 --- a/src/id3print.c +++ b/src/id3print.c @@ -33,12 +33,12 @@ void print_id3_tag(mpg123_handle *mh, int long_id3, FILE *out) if(v1 == NULL && v2 == NULL) return; if(v2 != NULL) /* fill from ID3v2 data */ { - transform(&tag[TITLE], &v2->title); - transform(&tag[ARTIST], &v2->artist); - transform(&tag[ALBUM], &v2->album); - transform(&tag[COMMENT], v2->generic_comment); - transform(&tag[YEAR], &v2->year); - transform(&tag[GENRE], &v2->genre); + transform(&tag[TITLE], v2->title); + transform(&tag[ARTIST], v2->artist); + transform(&tag[ALBUM], v2->album); + transform(&tag[COMMENT], v2->comment); + transform(&tag[YEAR], v2->year); + transform(&tag[GENRE], v2->genre); } if(v1 != NULL) /* fill gaps with ID3v1 data */ { diff --git a/src/libmpg123/id3.c b/src/libmpg123/id3.c index 89cfe194..a6ad2de3 100644 --- a/src/libmpg123/id3.c +++ b/src/libmpg123/id3.c @@ -34,80 +34,131 @@ const int encoding_widths[4] = { 1, 2, 2, 1 }; void init_id3(mpg123_handle *fr) { fr->id3v2.version = 0; /* nothing there */ - mpg123_init_string(&fr->id3v2.title); - mpg123_init_string(&fr->id3v2.artist); - mpg123_init_string(&fr->id3v2.album); - mpg123_init_string(&fr->id3v2.year); - mpg123_init_string(&fr->id3v2.genre); - fr->id3v2.comments = 0; - fr->id3v2.comment = NULL; - fr->id3v2.generic_comment = NULL; + fr->id3v2.title = NULL; + fr->id3v2.artist = NULL; + fr->id3v2.album = NULL; + fr->id3v2.year = NULL; + fr->id3v2.genre = NULL; + fr->id3v2.comments = 0; + fr->id3v2.comment_list = NULL; + fr->id3v2.texts = 0; + fr->id3v2.text = NULL; + fr->id3v2.extras = 0; + fr->id3v2.extra = NULL; } -static void free_comment(mpg123_handle *mh) +/* Managing of the text, comment and extra lists. */ + +/* Initialize one element. */ +static void init_mpg123_text(mpg123_text *txt) +{ + mpg123_init_string(&txt->text); + mpg123_init_string(&txt->description); + txt->id[0] = 0; + txt->id[1] = 0; + txt->id[2] = 0; + txt->id[3] = 0; + txt->lang[0] = 0; + txt->lang[1] = 0; + txt->lang[2] = 0; +} + +/* Free memory of one element. */ +static void free_mpg123_text(mpg123_text *txt) +{ + mpg123_free_string(&txt->text); + mpg123_init_string(&txt->description); +} + +/* Free memory of whole list. */ +#define free_comment(mh) free_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments)) +#define free_text(mh) free_id3_text(&((mh)->id3v2.text), &((mh)->id3v2.texts)) +#define free_extra(mh) free_id3_text(&((mh)->id3v2.extra), &((mh)->id3v2.extras)) +static void free_id3_text(mpg123_text **list, size_t *size) { size_t i; - mpg123_id3v2 *id = &mh->id3v2; - for(i=0; icomments; ++i) - { - mpg123_free_string(&id->comment[i].description); - mpg123_free_string(&id->comment[i].text); - } - free(id->comment); - id->comment = NULL; - id->comments = 0; - id->generic_comment = NULL; + for(i=0; i<*size; ++i) free_mpg123_text(&((*list)[i])); + + free(*list); + *list = NULL; + *size = 0; } -static mpg123_comment *add_comment(mpg123_handle *mh) +/* Add items to the list. */ +#define add_comment(mh) add_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments)) +#define add_text(mh) add_id3_text(&((mh)->id3v2.text), &((mh)->id3v2.texts)) +#define add_extra(mh) add_id3_text(&((mh)->id3v2.extra), &((mh)->id3v2.extras)) +static mpg123_text *add_id3_text(mpg123_text **list, size_t *size) { - mpg123_id3v2 *id = &mh->id3v2; - mpg123_comment *x = safe_realloc(id->comment, sizeof(mpg123_comment)*(id->comments+1)); + mpg123_text *x = safe_realloc(*list, sizeof(mpg123_text)*(*size+1)); if(x == NULL) return NULL; /* bad */ - id->comment = x; - id->comments += 1; - id->comment[id->comments-1].lang[0] = 0; /* empty... */ - mpg123_init_string(&id->comment[id->comments-1].description); - mpg123_init_string(&id->comment[id->comments-1].text); - return &id->comment[id->comments-1]; /* Return pointer to the added comment. */ + *list = x; + *size += 1; + init_mpg123_text(&((*list)[*size-1])); + + return &((*list)[*size-1]); /* Return pointer to the added text. */ } -static void pop_comment(mpg123_handle *mh) +/* Remove the last item. */ +#define pop_comment(mh) pop_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments)) +#define pop_text(mh) pop_id3_text(&((mh)->id3v2.text), &((mh)->id3v2.texts)) +#define pop_extra(mh) pop_id3_text(&((mh)->id3v2.extra), &((mh)->id3v2.extras)) +static void pop_id3_text(mpg123_text **list, size_t *size) { - mpg123_comment *x; - mpg123_id3v2 *id = &mh->id3v2; - if(id->comments < 1) return; + mpg123_text *x; + if(*size < 1) return; - mpg123_free_string(&id->comment[id->comments-1].description); - mpg123_free_string(&id->comment[id->comments-1].text); - x = safe_realloc(id->comment, sizeof(mpg123_comment)*(id->comments-1)); - if(x != NULL) + free_mpg123_text(&((*list)[*size-1])); + if(*size > 1) { - id->comment = x; - id->comments -= 1; + x = safe_realloc(*list, sizeof(mpg123_text)*(*size-1)); + if(x != NULL){ *list = x; *size -= 1; } + } + else + { + free(*list); + *list = NULL; + *size = 0; } } +/* OK, back t the higher level functions. */ + void exit_id3(mpg123_handle *fr) { - mpg123_free_string(&fr->id3v2.title); - mpg123_free_string(&fr->id3v2.artist); - mpg123_free_string(&fr->id3v2.album); - mpg123_free_string(&fr->id3v2.year); - mpg123_free_string(&fr->id3v2.genre); free_comment(fr); + free_extra(fr); + free_text(fr); } void reset_id3(mpg123_handle *fr) { - fr->id3v2.version = 0; - fr->id3v2.title.fill = 0; - fr->id3v2.artist.fill = 0; - fr->id3v2.album.fill = 0; - fr->id3v2.year.fill = 0; - fr->id3v2.genre.fill = 0; - free_comment(fr); + exit_id3(fr); + init_id3(fr); +} + +/* Set the id3v2.artist id3v2.title ... links to elements of the array. */ +void id3_link(mpg123_handle *fr) +{ + size_t i; + mpg123_id3v2 *v2 = &fr->id3v2; + for(i=0; itexts; ++i) + { + mpg123_text *entry = &v2->text[i]; + fprintf(stderr, "entry %i id %c%c%c%c at %p\n", i, entry->id[0], entry->id[1], entry->id[2], entry->id[3], &entry->text); + if (!strncmp("TIT2", entry->id, 4)) v2->title = &entry->text; + else if(!strncmp("TALB", entry->id, 4)) v2->album = &entry->text; + else if(!strncmp("TPE1", entry->id, 4)) v2->artist = &entry->text; + else if(!strncmp("TYER", entry->id, 4)) v2->year = &entry->text; + else if(!strncmp("TCON", entry->id, 4)) v2->genre = &entry->text; + } + for(i=0; icomments; ++i) + { + mpg123_text *entry = &v2->comment_list[i]; + if(entry->description.fill == 0 || entry->description.p[0] == 0) + v2->comment = &entry->text; + } } /* @@ -183,8 +234,23 @@ char *next_text(char* prev, int encoding, size_t limit) return text; } +static void process_text(mpg123_handle *fr, char *realdata, size_t realsize, char *id) +{ + /* Text encoding $xx */ + /* The text (encoded) ... */ + mpg123_text *t = add_text(fr); + if(t == NULL) + { + if(NOQUIET) error("Unable to attach new text!"); + return; + } + memcpy(t->id, id, 4); + store_id3_text(&t->text, realdata, realsize); + if(VERBOSE4) fprintf(stderr, "Note: ID3v2 %c%c%c%c text frame: %s\n", id[0], id[1], id[2], id[3], t->text.p); +} + /* Store a new comment that perhaps is a RVA / RVA_ALBUM/AUDIOPHILE / RVA_MIX/RADIO one */ -static void process_comment(mpg123_handle *fr, char *realdata, size_t realsize, int tt) +static void process_comment(mpg123_handle *fr, char *realdata, size_t realsize, int rva_level, char *id) { /* Text encoding $xx */ /* Language $xx xx xx */ @@ -194,13 +260,14 @@ static void process_comment(mpg123_handle *fr, char *realdata, size_t realsize, char *lang = realdata+1; /* I'll only use the 3 bytes! */ char *descr = realdata+4; char *text; - mpg123_comment *xcom = add_comment(fr); + mpg123_text *xcom = add_comment(fr); if(xcom == NULL) { if(NOQUIET) error("Unable to attach new comment!"); return; } memcpy(xcom->lang, lang, 3); + memcpy(xcom->id, id, 4); xcom->lang[3] = 0; /* Now I can abuse a byte from lang for the encoding. */ descr[-1] = encoding; @@ -233,76 +300,79 @@ static void process_comment(mpg123_handle *fr, char *realdata, size_t realsize, || !strcasecmp(xcom->description.p, "rva_audiophile") || !strcasecmp(xcom->description.p, "rva_user")) rva_mode = 1; - if((rva_mode > -1) && (fr->rva.level[rva_mode] <= tt+1)) + if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level)) { fr->rva.gain[rva_mode] = atof(xcom->text.p); if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]); fr->rva.peak[rva_mode] = 0; - fr->rva.level[rva_mode] = tt+1; + fr->rva.level[rva_mode] = rva_level; } } - /* Mark the last found generic comment. */ - if(xcom->description.fill == 0 || xcom->description.p[0] == 0) - fr->id3v2.generic_comment = &xcom->text; } -void process_extra(mpg123_handle *fr, char* realdata, size_t realsize, int tt) +void process_extra(mpg123_handle *fr, char* realdata, size_t realsize, int rva_level, char *id) { /* Text encoding $xx */ /* Description ... $00 (00) */ /* Text ... */ - mpg123_string work; char encoding = realdata[0]; char *descr = realdata+1; /* remember, the encoding is descr[-1] */ - char *text = next_text(descr, encoding, realsize-(descr-realdata)); + char *text; + mpg123_text *xex; + text = next_text(descr, encoding, realsize-(descr-realdata)); if(text == NULL) { if(NOQUIET) error("No extra frame text / valid description?"); return; } - mpg123_init_string(&work); - store_id3_text(&work, descr-1, text-descr+1); - if(work.fill > 0) + xex = add_extra(fr); + if(xex == NULL) + { + if(NOQUIET) error("Unable to attach new extra text!"); + return; + } + memcpy(xex->id, id, 4); + store_id3_text(&xex->description, descr-1, text-descr+1); + text[-1] = encoding; + store_id3_text(&xex->text, text-1, realsize-(text-realdata)+1); + if(xex->description.fill > 0) { int is_peak = 0; int rva_mode = -1; /* mix / album */ - if(!strncasecmp(work.p, "replaygain_track_",17)) + if(!strncasecmp(xex->description.p, "replaygain_track_",17)) { debug("ID3v2: track gain/peak"); rva_mode = 0; - if(!strcasecmp(work.p, "replaygain_track_peak")) is_peak = 1; - else if(strcasecmp(work.p, "replaygain_track_gain")) rva_mode = -1; + if(!strcasecmp(xex->description.p, "replaygain_track_peak")) is_peak = 1; + else if(strcasecmp(xex->description.p, "replaygain_track_gain")) rva_mode = -1; } else - if(!strncasecmp(work.p, "replaygain_album_",17)) + if(!strncasecmp(xex->description.p, "replaygain_album_",17)) { debug("ID3v2: album gain/peak"); rva_mode = 1; - if(!strcasecmp(work.p, "replaygain_album_peak")) is_peak = 1; - else if(strcasecmp(work.p, "replaygain_album_gain")) rva_mode = -1; + if(!strcasecmp(xex->description.p, "replaygain_album_peak")) is_peak = 1; + else if(strcasecmp(xex->description.p, "replaygain_album_gain")) rva_mode = -1; } - if((rva_mode > -1) && (fr->rva.level[rva_mode] <= tt+1)) + if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level)) { - text[-1] = encoding; - store_id3_text(&work, text-1, realsize-(text-realdata)+1); - if(work.fill > 0) + if(xex->text.fill > 0) { if(is_peak) { - fr->rva.peak[rva_mode] = atof(work.p); + fr->rva.peak[rva_mode] = atof(xex->text.p); if(VERBOSE3) fprintf(stderr, "Note: RVA peak %fdB\n", fr->rva.peak[rva_mode]); } else { - fr->rva.gain[rva_mode] = atof(work.p); + fr->rva.gain[rva_mode] = atof(xex->text.p); if(VERBOSE3) fprintf(stderr, "Note: RVA gain %fdB\n", fr->rva.gain[rva_mode]); } - fr->rva.level[rva_mode] = tt+1; + fr->rva.level[rva_mode] = rva_level; } } } - mpg123_free_string(&work); } /* @@ -401,9 +471,9 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes) unsigned long pos = tagpos; /* level 1,2,3 - 0 is info from lame/info tag! */ /* rva tags with ascending significance, then general frames */ - #define KNOWN_FRAMES 8 - const char frame_type[KNOWN_FRAMES][5] = { "COMM", "TXXX", "RVA2", "TPE1", "TALB", "TIT2", "TYER", "TCON" }; - enum { egal = -1, comment, extra, rva2, artist, album, title, year, genre } tt = egal; + #define KNOWN_FRAMES 3 + const char frame_type[KNOWN_FRAMES][5] = { "COMM", "TXXX", "RVA2" }; /* plus all text frames... */ + enum { unknown = -2, text = -1, comment, extra, rva2 } tt = unknown; /* we may have entered the padding zone or any other strangeness: check if we have valid frame id characters */ for(; i< 4; ++i) if( !( ((tagdata[tagpos+i] > 47) && (tagdata[tagpos+i] < 58)) || ((tagdata[tagpos+i] > 64) && (tagdata[tagpos+i] < 91)) ) ) @@ -450,8 +520,10 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes) for(i = 0; i < KNOWN_FRAMES; ++i) if(!strncmp(frame_type[i], id, 4)){ tt = i; break; } - - if(tt != egal) + + if(id[0] == 'T' && tt != extra) tt = text; + + if(tt != unknown) { int rva_mode = -1; /* mix / album */ unsigned long realsize = framesize; @@ -487,10 +559,10 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes) switch(tt) { case comment: - process_comment(fr, (char*)realdata, realsize, tt); + process_comment(fr, (char*)realdata, realsize, comment+1, id); break; case extra: /* perhaps foobar2000's work */ - process_extra(fr, (char*)realdata, realsize, tt); + process_extra(fr, (char*)realdata, realsize, extra+1, id); break; case rva2: /* "the" RVA tag */ { @@ -503,7 +575,7 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes) || !strncasecmp((char*)realdata, "audiophile", 10) || !strncasecmp((char*)realdata, "user", 4)) rva_mode = 1; - if(fr->rva.level[rva_mode] <= tt+1) + if(fr->rva.level[rva_mode] <= rva2+1) { pos += strlen((char*) realdata) + 1; if(realdata[pos] == 1) @@ -519,7 +591,7 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes) if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]); /* heh, the peak value is represented by a number of bits - but in what manner? Skipping that part */ fr->rva.peak[rva_mode] = 0; - fr->rva.level[rva_mode] = tt+1; + fr->rva.level[rva_mode] = rva2+1; } } #else @@ -528,25 +600,8 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes) } break; /* non-rva metainfo, simply store... */ - case artist: - debug("ID3v2: parsing artist info"); - store_id3_text(&fr->id3v2.artist, (char*) realdata, realsize); - break; - case album: - debug("ID3v2: parsing album info"); - store_id3_text(&fr->id3v2.album, (char*) realdata, realsize); - break; - case title: - debug("ID3v2: parsing title info"); - store_id3_text(&fr->id3v2.title, (char*) realdata, realsize); - break; - case year: - debug("ID3v2: parsing year info"); - store_id3_text(&fr->id3v2.year, (char*) realdata, realsize); - break; - case genre: - debug("ID3v2: parsing genre info"); - store_id3_text(&fr->id3v2.genre, (char*) realdata, realsize); + case text: + process_text(fr, (char*)realdata, realsize, id); break; default: error1("ID3v2: unknown frame type %i", tt); } diff --git a/src/libmpg123/id3.h b/src/libmpg123/id3.h index 8910b329..dc10e94a 100644 --- a/src/libmpg123/id3.h +++ b/src/libmpg123/id3.h @@ -16,5 +16,6 @@ void init_id3(mpg123_handle *fr); void exit_id3(mpg123_handle *fr); void reset_id3(mpg123_handle *fr); int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes); +void id3_link(mpg123_handle *fr); #endif diff --git a/src/libmpg123/libmpg123.c b/src/libmpg123/libmpg123.c index 343a9d74..bdc35d92 100644 --- a/src/libmpg123/libmpg123.c +++ b/src/libmpg123/libmpg123.c @@ -897,6 +897,7 @@ int mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2) if(mh->metaflags & MPG123_ID3) { + id3_link(mh); if(v1 != NULL && mh->rdat.flags & READER_ID3TAG) *v1 = (mpg123_id3v1*) mh->id3buf; if(v2 != NULL) *v2 = &mh->id3v2; mh->metaflags |= MPG123_ID3; diff --git a/src/libmpg123/mpg123.h.in b/src/libmpg123/mpg123.h.in index bce7a083..511f6aca 100644 --- a/src/libmpg123/mpg123.h.in +++ b/src/libmpg123/mpg123.h.in @@ -566,13 +566,17 @@ EXPORT int mpg123_add_string(mpg123_string* sb, char* stuff); * \return 0 on error, 1 on success */ EXPORT int mpg123_set_string(mpg123_string* sb, char* stuff); -/** Sub data structure for ID3v2, for storing comments. */ +/** Sub data structure for ID3v2, for storing various text fields (including comments). + * This is for ID3v2 COMM, TXXX and all the other text fields. + * Only COMM and TXXX have a description, only COMM has a language. + * You should consult the ID3v2 specification for the use of the various text fields ("frames" in ID3v2 documentation, I use "fields" here to separate from MPEG frames). */ typedef struct { - char lang[4]; /**< Three-letter language code (null-terminated). */ + char lang[3]; /**< Three-letter language code (not terminated). */ + char id[4]; /**< The ID3v2 text field id, like TALB, TPE2, ... (4 characters, no string termination). */ mpg123_string description; /**< Empty for the generic comment... */ mpg123_string text; /**< ... */ -} mpg123_comment; +} mpg123_text; /** Data structure for storing IDV3v2 tags. * This structure is not a direct binary mapping with the file contents. @@ -582,14 +586,20 @@ typedef struct typedef struct { unsigned char version; /**< 3 or 4 for ID3v2.3 or ID3v2.4. */ - mpg123_string title; /**< Title string. */ - mpg123_string artist; /**< Artist string. */ - mpg123_string album; /**< Album string. */ - mpg123_string year; /**< The year as a string. */ - mpg123_string genre; /**< Genre String. The genre string(s) may very well need postprocessing, esp. for ID3v2.3. */ - size_t comments; /**< Number of comments. */ - mpg123_comment *comment; /**< Array of comments. */ - mpg123_string *generic_comment; /**< Pointer to last encountered comment text with empty description. */ + mpg123_string *title; /**< Title string (pointer into text_list). */ + mpg123_string *artist; /**< Artist string (pointer into text_list). */ + mpg123_string *album; /**< Album string (pointer into text_list). */ + mpg123_string *year; /**< The year as a string (pointer into text_list). */ + mpg123_string *genre; /**< Genre String (pointer into text_list). The genre string(s) may very well need postprocessing, esp. for ID3v2.3. */ + mpg123_string *comment; /**< Pointer to last encountered comment text with empty description. */ + /* Encountered ID3v2 fields are appended to these lists. + There can be multiple occurences, the pointers above always point to the last encountered data. */ + mpg123_text *comment_list; /**< Array of comments. */ + size_t comments; /**< Number of comments. */ + mpg123_text *text; /**< Array of ID3v2 text fields */ + size_t texts; /**< Numer of text fields. */ + mpg123_text *extra; /**< The array of extra (TXXX) fields. */ + size_t extras; /**< Number of extra text (TXXX) fields. */ } mpg123_id3v2; /** Data structure for ID3v1 tags (the last 128 bytes of a file). diff --git a/src/libmpg123/stringbuf.c b/src/libmpg123/stringbuf.c index 73664b7e..c687ef68 100644 --- a/src/libmpg123/stringbuf.c +++ b/src/libmpg123/stringbuf.c @@ -53,14 +53,25 @@ int mpg123_resize_string(mpg123_string* sb, size_t new) int mpg123_copy_string(mpg123_string* from, mpg123_string* to) { + size_t fill; + char *text; if(to == NULL) return -1; - if(from == NULL) return mpg123_set_string(to, ""); - - if(mpg123_resize_string(to, from->fill)) + if(from == NULL) { - memcpy(to->p, from->p, to->size); - to->fill = to->size; + fill = 0; + text = NULL; + } + else + { + fill = from->fill; + text = from->p; + } + + if(mpg123_resize_string(to, fill)) + { + memcpy(to->p, text, fill); + to->fill = fill; return 1; } else return 0;