From 4412ca091e6379def8bc836163c6b580df76619c Mon Sep 17 00:00:00 2001 From: crunchy Date: Wed, 23 Apr 2003 08:34:01 +0000 Subject: start restructuring --- libmpio/mplib/mplib.c | 1011 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1011 insertions(+) create mode 100644 libmpio/mplib/mplib.c (limited to 'libmpio/mplib/mplib.c') diff --git a/libmpio/mplib/mplib.c b/libmpio/mplib/mplib.c new file mode 100644 index 0000000..afa7066 --- /dev/null +++ b/libmpio/mplib/mplib.c @@ -0,0 +1,1011 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include +# include +#elif HAVE_STRINGS_H +# include +#endif /*STDC_HEADERS*/ + +#if HAVE_UNISTD_H +# include +# include +#endif + +#include +#include +#include + +#include "xmalloc.h" +#include "mplib.h" +#include "mplib_s.h" +#include "mplib_s.c" + + + +/******************************************************************************************* + * Extern functions + *******************************************************************************************/ + + + +/******************************************************************************************* + * Get + *******************************************************************************************/ + + mpeg_header* + mp_get_mpeg_header_from_file(const char* filename) + { + mpeg_header *ret; + int fd; + + if(!filename) return NULL; + + fd = open(filename, O_RDONLY); + if(fd == -1) return NULL; + + ret = mp_get_mpeg_header_from_fd(fd); + close(fd); + return ret; + } + + +mpeg_header* +mp_get_mpeg_header_from_fd(int fd) +{ + mpeg_header *h; + unsigned char c[5]; + + h = XMALLOCD(mpeg_header, "mp_get_mpeg_header_from_fd:h"); + + if(id3_lseek_syncword(fd)) goto exit_on_error; + + if(read(fd, c, 4) < 4) goto exit_on_error; + + memset(h, 0, sizeof(h)); + h->syncword = (c[1] & 240); + h->syncword <<= 8; + h->syncword |= c[0]; + h->version = (c[1] & 8) >> 3; + h->layer = (c[1] & 6) >> 1; + h->protbit = (c[1] & 1); + h->bitrate = (c[2] & 240) >> 4; + h->samplingfreq = (c[2] & 12) >> 2; + h->padbit = (c[2] & 2) >> 1; + h->privbit = (c[2] & 1); + h->mode = (c[3] & 192) >> 6; + h->mode_ext = (c[3] & 48) >> 4; + h->copyright = (c[3] & 8) >> 3; + h->originalhome = (c[3] & 4) >> 2; + h->emphasis = (c[3] & 3); + + return h; + + exit_on_error: + xfree(h); + return NULL; +} + +char* +mp_get_str_version(const mpeg_header *h) +{ + return h->version == 0 ? "MPEG 2" : "MPEG 1"; +} + +char* +mp_get_str_layer(const mpeg_header *h) +{ + switch(h->layer) + { + case 1: return "Layer III"; + case 2: return "Layer II"; + case 3: return "Layer I"; + default: return "undefined"; + } +} + +char* +mp_get_str_bitrate(const mpeg_header *h) +{ + char *buf = (char *)xmallocd0(11, "mp_get_str_bitrate:buf"); + + if(h->version == 1) /* MPEG 1 */ + { + switch(h->layer) + { + case 1: + snprintf(buf, sizeof buf, "%d kBit/s", br_1_3[h->bitrate]); + return buf; + case 2: + snprintf(buf, sizeof buf, "%d kBit/s", br_1_2[h->bitrate]); + return buf; + case 3: + snprintf(buf, sizeof buf, "%d kBit/s", br_1_1[h->bitrate]); + return buf; + default: + return "undefined"; + } + } + else /* MPEG 2 */ + { + switch(h->layer) + { + case 1: + snprintf(buf, sizeof buf, "%d kBit/s", br_2_3[h->bitrate]); + return buf; + case 2: + snprintf(buf, sizeof buf, "%d kBit/s", br_2_2[h->bitrate]); + return buf; + case 3: + snprintf(buf, sizeof buf, "%d kBit/s", br_2_1[h->bitrate]); + return buf; + default: + return "undefined"; + } + } +} + +char* +mp_get_str_samplingfreq(const mpeg_header *h) +{ + if(h->version == 1) + { + switch(h->samplingfreq) + { + case 0: return "44100 Hz"; + case 1: return "48000 Hz"; + case 2: return "32000 Hz"; + default: return "undefined"; + } + } + else + { + switch(h->samplingfreq) + { + case 0: return "22050 Hz"; + case 1: return "24000 Hz"; + case 2: return "16000 Hz"; + default: return "undefined"; + } + } +} + +char* +mp_get_str_mode(const mpeg_header *h) +{ + switch(h->mode) + { + case 0: return "Stereo"; + case 1: return "Joint-Stereo"; + case 2: return "Dual-Channel"; + case 3: return "Mono"; + default: return "undefined"; + } +} + +id3_tag_list* +mp_get_tag_list_from_file(const char* filename) +{ + id3_tag_list *ret; + int fd; + + if(!filename) return NULL; + + fd = open(filename, O_RDONLY); + if(fd == -1) return NULL; + + ret = mp_get_tag_list_from_fd(fd); + close(fd); + return ret; +} + +id3_tag_list* +mp_get_tag_list_from_fd(int fd) +{ + id3_tag_list *tag_list = NULL; + id3_tag_list *tag_list2 = NULL; + id3v2_tag *v2tag = NULL; + id3v1_tag *v1tag = NULL; + id3_tag *tag = NULL; + + v2tag = id3v2_get_tag(fd); + if(v2tag) + { + tag = XMALLOCD0(id3_tag, "mp_get_tag_list_from_fd:tag"); + if(v2tag->header->version_minor == 3 || v2tag->header->version_minor == 4) + tag->version = 2; + else + tag->version = -1; + tag->tag = v2tag; + + tag_list = XMALLOCD(id3_tag_list, "mp_get_tag_list_from_fd:tag_list"); + tag_list->tag = tag; + tag_list->next = NULL; + tag_list->first = tag_list; + } + + v1tag = id3v1_get_tag(fd); + if(v1tag) + { + tag = XMALLOCD(id3_tag, "mp_get_tag_list_from_fd:tag"); + tag->version = 1; + tag->tag = v1tag; + + if(tag_list) + { + tag_list2 = XMALLOCD(id3_tag_list, "mp_get_tag_list_from_fd:tag_list2"); + tag_list2->tag = tag; + tag_list2->next = NULL; + tag_list2->first = tag_list; + tag_list->next = tag_list2; + } + else + { + tag_list = XMALLOCD(id3_tag_list, "mp_get_tag_list_from_fd:tag_list"); + tag_list->tag = tag; + tag_list->next = NULL; + tag_list->first = tag_list; + } + } + + return tag_list; +} + +id3_content* +mp_get_content(const id3_tag *tag, int field) +{ + return mp_get_content_at_pos(tag, field, 0); +} + +id3_content* +mp_get_content_at_pos(const id3_tag *tag, int field, int pos) +{ + int i; + char *c; + id3_content *ret; + + if(!tag || !tag->tag) + { + errno = MP_EERROR; + return NULL; + } + + if(tag->version == 1) + { + if(pos != 0) + { + errno = MP_EERROR; + return NULL; + } + else return id3v1_get_content(tag->tag, field); + } + else if(tag->version == 2) + { + id3v2_tag *v2 = tag->tag; + char *val; + + switch(field) + { + case MP_ARTIST: + return mp_get_content_custom_at_pos(tag, "TPE1", pos); + case MP_TITLE: + return mp_get_content_custom_at_pos(tag, "TIT2", pos); + case MP_ALBUM: + return mp_get_content_custom_at_pos(tag, "TALB", pos); + case MP_GENRE: + return mp_get_content_custom_at_pos(tag, "TCON", pos); + case MP_COMMENT: + return mp_get_content_custom_at_pos(tag, "COMM", pos); + case MP_YEAR: + return mp_get_content_custom_at_pos(tag, "TYER", pos); + case MP_TRACK: + return mp_get_content_custom_at_pos(tag, "TRCK", pos); + } + errno = MP_EFNF; + return NULL; + } + else + { + errno = MP_EVERSION; + return NULL; + } +} + +id3_content* +mp_get_content_custom(const id3_tag* tag, const char*field) +{ + if(!tag) + { + errno = MP_EERROR; + return NULL; + } + else if(tag->version != 2) + { + errno = MP_EVERSION; + return NULL; + } + + return id3v2_get_content_at_pos(tag->tag, field, 0); + +} + +id3_content* +mp_get_content_custom_at_pos(const id3_tag* tag, const char*field, int pos) +{ + if(!tag) + { + errno = MP_EERROR; + return NULL; + } + else if(tag->version != 2) + { + errno = MP_EVERSION; + return NULL; + } + + + return id3v2_get_content_at_pos(tag->tag, field, pos); +} + + +/******************************************************************************************* + * Set + *******************************************************************************************/ + + int + mp_set_content(id3_tag* tag, const int field, id3_content* new_content) + { + id3v1_tag *v1; + id3v2_tag *v2; + + + if(!tag) return MP_EERROR; + + if(tag->version == 2) + { + return mp_set_content_at_pos(tag, field, new_content, 0); + } + else if(tag->version == 1) + { + unsigned char c; + char *my_val; + int len, j; + + v1 = tag->tag; + + switch(field) + { + +#define FLD(str1, str2, str3, str4) \ + case str1:\ + if(!new_content) v1->str2 = NULL;\ + else\ + {\ + id3_text_content *tc = str4(new_content);\ + if(strlen(tc->text) > str3 || tc->encoding != ISO_8859_1)\ + {\ + mp_convert_to_v2(tag);\ + mp_free_text_content(tc);\ + return mp_set_content(tag, field, new_content);\ + }\ + \ + v1->str2 = tc->text;\ + xfree(tc);\ + }\ + break; + + FLD(MP_ARTIST, artist, 30, mp_parse_artist); + FLD(MP_TITLE, title, 30, mp_parse_title); + FLD(MP_ALBUM, album, 30, mp_parse_album); + FLD(MP_YEAR, year, 4, mp_parse_year); + + case MP_COMMENT: + if(!new_content) v1->comment = NULL; + else + { + id3_comment_content *tc = mp_parse_comment(new_content); + if(strlen(tc->text) > 30 || tc->short_descr || tc->encoding != ISO_8859_1) + { + mp_convert_to_v2(tag); + mp_free_comment_content(tc); + return mp_set_content(tag, field, new_content); + } + v1->comment = xmallocd0(strlen(tc->text)+1, + "mp_set_content:v1->comment"); + memcpy(v1->comment, tc->text, strlen(tc->text)); + mp_free_comment_content(tc); + } + break; + + case MP_TRACK: + if(!new_content) v1->track = 0; + else + { + id3_text_content *tc = mp_parse_track(new_content); +#ifdef HAVE_STRTOL + errno = 0; + j = strtol(tc->text, (char **)NULL, 10); + if(errno != ERANGE) v1->track = j; + else return MP_EERROR; +#else + v1->track = atoi(tc->text); +#endif + mp_free_text_content(tc); + } + break; + + case MP_GENRE: + if(!new_content) v1->genre = 0xFF; + else + { + int b = 0, i; + id3_text_content *tc = mp_parse_genre(new_content); + /* i = strlen(tc->text); */ + for(c = 0; c < GLL; c++) { + if(!strcmp(genre_list[c], tc->text)) + { + v1->genre = c; + b = 1; + } + } + mp_free_text_content(tc); + if(!b) + { + mp_convert_to_v2(tag); + return mp_set_content(tag, field, new_content); + } + break; + } + } + } + else if(tag->version == -1) return MP_EVERSION; + else return MP_EFNF; + + return 0; + } + +int +mp_set_content_at_pos(id3_tag* tag, const int field, id3_content* new_content, int pos) +{ + char* c; + + if(!tag) return MP_EERROR; + if(field < MP_ARTIST || field > MP_TRACK) return MP_EFNF; + + if(tag->version == 1 && pos == 0) return mp_set_content(tag, field, new_content); + + switch(field) + { + case MP_ARTIST: c = "TPE1"; break; + case MP_TITLE: c = "TIT2"; break; + case MP_ALBUM: c = "TALB"; break; + case MP_TRACK: c = "TRCK"; break; + case MP_YEAR: c = "TYER"; break; + case MP_COMMENT: c = "COMM"; break; + case MP_GENRE: c = "TCON"; break; + } + return mp_set_custom_content_at_pos(tag, c, new_content, pos); +} + +int +mp_set_custom_content(id3_tag* tag, char* field, id3_content* new_content) +{ + return mp_set_custom_content_at_pos(tag, field, new_content, 0); +} + +int +mp_set_custom_content_at_pos(id3_tag* tag, char* field, id3_content* new_content, int pos) +{ + id3v2_tag *v2; + + if(!tag || !field || strlen(field) != 4) return MP_EERROR; + + if(tag->version == 1) + { + if(mp_convert_to_v2(tag)) + return MP_EERROR; + } + else if(tag->version == -1) return MP_EVERSION; + + v2 = (id3v2_tag*)tag->tag; + if(!v2->frame_list) + { + v2->frame_list = XMALLOCD0(id3v2_frame_list, + "mp_set_custom_content_at_pos:v2->frame_list"); + id3_add_frame(v2->frame_list, field, new_content->data, new_content->length); + } + else + { + id3v2_frame *frame; + + if((frame = id3_lookup_frame(v2->frame_list, field, pos))) + { + if(new_content) + { + long len, len_sync; + /* make sync safe */ + len = new_content->length; + len_sync = id3_sync(new_content->data, len); + + xfree(frame->data); + frame->data = xmallocd(new_content->length, + "mp_set_custom_content_at_pos:frame->data"); + memcpy(frame->data, new_content->data, new_content->length); + frame->status_flag = 0; + if(len != len_sync) frame->format_flag = 64; + else frame->format_flag = 0; + frame->data_size = len_sync; + } + else id3_remove_frame(v2->frame_list, frame); + } + else if(pos == 0) id3_add_frame(v2->frame_list, field, new_content->data, new_content->length); + else return MP_EFNF; + } + + return 0; +} + +/******************************************************************************************* + * Write & delete + *******************************************************************************************/ + int + mp_write_to_file(const id3_tag_list* tag_list, const char *filename) + { + int ret; + int fd; + + if(!filename) return MP_EERROR; + + fd = open(filename, O_RDWR); + if(fd == -1) return MP_EERROR; + + ret = mp_write_to_fd(tag_list, fd); + close(fd); + return ret; + } + + + int + mp_write_to_fd(const id3_tag_list* tag_list, const int fd) + { + id3_tag *tag; + id3v1_tag *v1; + id3v2_tag *v2; + id3_tag_list *mylist; + int ret = 0; + + if(!tag_list) { + ret |= id3v1_del_tag(fd); + ret |= id3v2_del_tag(fd, NULL); + return ret; + } + + while(tag_list) + { + tag = tag_list->tag; + if(!tag) + { + tag_list = tag_list->next; + continue; + } + + if(tag->version == 1) + { + id3v1_del_tag(fd); + ret |= id3v1_add_tag(fd, tag->tag); + } + else if(tag->version == 2) + { + int pad = 0; + id3v2_frame_list *frame_list; + id3v2_tag *old_v2; + id3v2_tag *v2 = tag->tag; + + /* calculate tag size */ + v2->header->total_tag_size = 10; + if(v2->header->has_footer) v2->header->total_tag_size += 10; + if(v2->header->has_extended_header) v2->header->total_tag_size += v2->header->extended_header->size; + frame_list = v2->frame_list; + while(frame_list) + { + v2->header->total_tag_size += frame_list->data->data_size + 10; + frame_list = frame_list->next; + } + + /* this is where padding handling takes place */ + /* we must get the old tag to see if padding can be used */ + old_v2 = id3v2_get_tag(fd); + if(old_v2) { + if(v2->header->total_tag_size > old_v2->header->total_tag_size) + { + /* padding not sufficent */ + ret |= id3v2_del_tag(fd, old_v2); + ret |= id3v2_add_tag(fd, v2, NULL); + } + else + { + ret |= id3v2_add_tag(fd, v2, old_v2); + } + id3v2_free_tag(old_v2); + } else { + ret |= id3v2_add_tag(fd, v2, NULL); + } + + } + else + { + ret |= MP_EVERSION; + } + + tag_list = tag_list->next; + } /* tag list */ + + return ret; + } + +int +mp_del_tags_from_file(const char* filename) +{ + int ret, fd; + + if(!filename) return 1; + + fd = open(filename, O_RDWR); + if(fd == -1) return 1; + + ret = mp_del_tags_from_fd(fd); + close(fd); + return ret; +} + +int +mp_del_tags_from_fd(const int fd) +{ + int ret = 0; + + ret |= id3v1_del_tag(fd); + ret |= id3v2_del_tag(fd, NULL); + + return ret; +} + +int +mp_del_tags_by_ver_from_file(const char* filename, const int version) +{ + int fd, ret; + + if(!filename) return 1; + + fd = open(filename, O_RDWR); + if(fd == -1) return 1; + + ret = mp_del_tags_by_ver_from_fd(fd, version); + close(fd); + return ret; +} + +int +mp_del_tags_by_ver_from_fd(const int fd, const int version) +{ + if(version == 1) return id3v1_del_tag(fd); + else if(version == 2) return id3v2_del_tag(fd, NULL); + else return MP_EVERSION; +} + + + + +/******************************************************************************************* + * Misc + *******************************************************************************************/ + + int + mp_convert_to_v2(id3_tag *tag) + { + id3v1_tag *v1; + id3_tag *tmp; + id3_content* content; + + if(tag->version == 2) return 0; + else if(tag->version == -1) return MP_EVERSION; + + tmp = mp_alloc_tag_with_version(2); + + v1 = (id3v1_tag*)tag->tag; + + content = mp_assemble_text_content(v1->artist, ISO_8859_1); + if(v1->artist) mp_set_content(tmp, MP_ARTIST, content); + + content = mp_assemble_text_content(v1->title, ISO_8859_1); + if(v1->title) mp_set_content(tmp, MP_TITLE, content); + + content = mp_assemble_text_content(v1->album, ISO_8859_1); + if(v1->album) mp_set_content(tmp, MP_ALBUM, content); + + content = mp_assemble_text_content(v1->year, ISO_8859_1); + if(v1->year) mp_set_content(tmp, MP_YEAR, content); + + content = mp_assemble_comment_content(v1->comment, NULL, ISO_8859_1, NULL); + if(v1->comment) mp_set_content(tmp, MP_COMMENT, content); + + if(v1->genre != 0xFF) + { + char *c = xmallocd(strlen(genre_list[v1->genre]) + 1, + "mp_convert_to_v2:c"); + strcpy(c, genre_list[v1->genre]); + content = mp_assemble_text_content(c, ISO_8859_1); + mp_set_content(tmp, MP_GENRE, content); + } + if(v1->track > 0) + { + char *trk = (char *)xmallocd(4, "mp_convert_to_v2:trk"); + snprintf(trk, 3, "%d", v1->track); + trk[3] = 0; + content = mp_assemble_text_content(trk, ISO_8859_1); + mp_set_content(tmp, MP_TRACK, content); + } + + tag->version = 2; + tag->tag = tmp->tag; + + id3v1_free_tag(v1); + xfree(tmp); + + return 0; + } + +int +mp_convert_to_v1(id3_tag *tag) +{ + id3v1_tag *v1; + id3_tag* tmp; + id3_content* content; + id3_text_content* tc; + id3_comment_content* cc; + char* c; + int j, k = 0; + + if(tag->version == 1) return 0; + else if(tag->version == -1) return MP_EVERSION; + + v1 = XMALLOCD0(id3v1_tag, "mp_convert_to_v1:v1"); + + content = mp_get_content(tag, MP_ARTIST); + tc = mp_parse_artist(content); + v1->artist = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_TITLE); + tc = mp_parse_title(content); + v1->title = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_ALBUM); + tc = mp_parse_album(content); + v1->album = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_YEAR); + tc = mp_parse_year(content); + v1->year = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_COMMENT); + cc = mp_parse_comment(content); + v1->comment = cc->text; + xfree(cc->language); + xfree(cc->short_descr); + xfree(cc); + mp_free_content(content); + + content = mp_get_content(tag, MP_TRACK); + tc = mp_parse_track(content); + c = tc->text; + if(c) + { +#ifdef HAVE_STRTOL + errno = 0; + j = strtol(c, (char **)NULL, 10); + if(errno != ERANGE) v1->track = j; + else v1->track = 0; +#else + v1->track = atoi(c); +#endif + } + else v1->track = 0; + xfree(c); + mp_free_text_content(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_GENRE); + tc = mp_parse_genre(content); + c = tc->text; + for(j = 0; c, j < GLL; j++) { + if(!strcmp(genre_list[j], c)) + { + v1->genre = j; + k = 1; + } + } + if(!c) v1->genre = 0xFF; + xfree(c); + mp_free_text_content(tc); + mp_free_content(content); + + id3v1_truncate_tag(v1); + + id3v2_free_tag(tag->tag); + + tag->version = 1; + tag->tag = v1; + + return 0; +} + +int +mp_is_valid_v1_value(int field, char *value) +{ + int len = 30; + int j; + + switch(field) { + case MP_YEAR: + len = 4; + break; + + case MP_TRACK: +#ifdef HAVE_STRTOL + errno = 0; + j = strtol(value, (char **)NULL, 10); + if(errno != ERANGE) return 1; + else return 0; +#else + return 1; /* poor fellow */ +#endif + + case MP_GENRE: + for(j = 0; j < GLL; j++) { + if(!strcmp(genre_list[j], value)) + { + return 1; + } + return 0; + } + } + + /* Check string length */ + if(strlen(value) > len) return 0; + else return 1; +} + + +void +mp_free_list(id3_tag_list *list) +{ + if(!list) return; + + /* free tag */ + if(list->tag) mp_free_tag(list->tag); + + /* free next element */ + if(list->next) mp_free_list(list->next); + + /* free this element */ + xfree(list); +} + +id3_tag* +mp_alloc_tag(void) +{ + /* The tags initialized version makes a different. Generally spoken, we + like to make id3v1 tags if possible and therefor set the version to 1 + here. This matters in mp_set_content(). */ + return mp_alloc_tag_with_version(1); +} + +id3_tag* +mp_alloc_tag_with_version(int v) +{ + id3_tag* ret; + + if(v != 1 && v != 2) return NULL; + + ret = XMALLOCD(id3_tag, "mp_alloc_tag_with_version:ret"); + ret->version = v; + if(v == 1) + { + ret->tag = XMALLOCD0(id3v1_tag, "mp_alloc_tag_with_version:ret->tag"); + ((id3v1_tag*)ret->tag)->genre = 0xFF; + } + else + { + id3v2_tag *v2; + /* XXX */ + ret->tag = XMALLOCD0(id3v2_tag, "mp_alloc_tag_with_version:ret->tag"); + v2 = (id3v2_tag*)ret->tag; + v2->header = XMALLOCD0(id3v2_header, "mp_alloc_tag_with_version:v2->header"); +//if ID3VERSION == "2.4" + v2->header->version_minor = 4; +//else + v2->header->version_minor = 3; +//endif + v2->header->version_revision = 0; + v2->header->unsyncronization = 1; + v2->header->has_extended_header = 0; + v2->header->is_experimental = 1; + v2->header->has_footer = 0; + v2->header->flags = 0; + v2->header->total_tag_size = 0; + v2->header->extended_header = NULL; + v2->frame_list = NULL; + } + return ret; +} + +void +mp_free_tag(id3_tag *tag) +{ + if(!tag) return; + + if(tag->version == 1) + { + id3v1_free_tag(tag->tag); + } + else if(tag->version == 2) + { + id3v2_free_tag(tag->tag); + } + xfree(tag); +} + +void +mp_free_content(id3_content *content) +{ + if(!content) return; + xfree(content->data); + xfree(content); +} + +void +mp_free_text_content(id3_text_content *content) +{ + if(!content) return; + xfree(content->text); + xfree(content); +} + +void +mp_free_comment_content(id3_comment_content *content) +{ + if(!content) return; + xfree(content->language); + xfree(content->short_descr); + xfree(content->text); + xfree(content); +} + + -- cgit v1.2.3