static int v1_attachstr(struct id3_tag *tag, char const *id, char *text, unsigned long number) { struct id3_frame *frame; id3_ucs4_t ucs4[31]; if (text) { trim(text); if (*text == 0) return 0; } frame = id3_frame_new(id); if (frame == 0) return -1; if (id3_field_settextencoding(&frame->fields[0], ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1) goto fail; if (text) id3_latin1_decode(text, ucs4); else id3_ucs4_putnumber(ucs4, number); if (strcmp(id, ID3_FRAME_COMMENT) == 0) { if (id3_field_setlanguage(&frame->fields[1], "XXX") == -1 || id3_field_setstring(&frame->fields[2], id3_ucs4_empty) == -1 || id3_field_setfullstring(&frame->fields[3], ucs4) == -1) goto fail; } else { id3_ucs4_t *ptr = ucs4; if (id3_field_setstrings(&frame->fields[1], 1, &ptr) == -1) goto fail; } if (id3_tag_attachframe(tag, frame) == -1) goto fail; return 0; fail: id3_frame_delete(frame); return -1; }
int id3_metadata_setcomment(struct id3_tag* tag, id3_ucs4_t* value) { union id3_field *field; struct id3_frame *frame; frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, 0); if (frame == 0) { frame = id3_frame_new(ID3_FRAME_COMMENT); id3_tag_attachframe(tag, frame); } id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16); field = id3_frame_field(frame, 3); if (field == 0) return 0; return id3_field_setfullstring(field, value); }
int metadata_setstring(struct id3_tag* tag, const char* id, id3_ucs4_t* value) { union id3_field *field; struct id3_frame *frame; frame = id3_tag_findframe(tag, id, 0); if (frame == 0) { frame = id3_frame_new(id); id3_tag_attachframe(tag, frame); } id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16); field = id3_frame_field(frame, 1); if (field == 0) return 0; return (id3_field_setstrings(field, 1, &value)==0); }
void ExportMP2::AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name) { struct id3_frame *frame = id3_frame_new(name); if (!n.IsAscii() || !v.IsAscii()) { id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16); } else { id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1); } id3_ucs4_t *ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); if (strcmp(name, ID3_FRAME_COMMENT) == 0) { // A hack to get around iTunes not recognizing the comment. The // language defaults to XXX and, since it's not a valid language, // iTunes just ignores the tag. So, either set it to a valid language // (which one???) or just clear it. Unfortunately, there's no supported // way of clearing the field, so do it directly. id3_field *f = id3_frame_field(frame, 1); memset(f->immediate.value, 0, sizeof(f->immediate.value)); id3_field_setfullstring(id3_frame_field(frame, 3), ucs4); } else if (strcmp(name, "TXXX") == 0) { id3_field_setstring(id3_frame_field(frame, 2), ucs4); free(ucs4); ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)); id3_field_setstring(id3_frame_field(frame, 1), ucs4); } else { id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4); } free(ucs4); id3_tag_attachframe(tp, frame); }
int id3_metadata_setrating(struct id3_tag* tag, char value) { union id3_field *field; struct id3_frame *frame; char popm[] = { 3, 53, 104, 154, 205, 255 }; if (value < '0' || value > '5') return -1; frame = id3_tag_findframe(tag, "POPM", 0); if (frame == 0) { frame = id3_frame_new("POPM"); id3_tag_attachframe(tag, frame); } field = id3_frame_field(frame, 1); if (field == 0) return 0; return id3_field_setint(field, popm[value - '0']); }
static struct id3_tag *v2_parse(id3_byte_t const *ptr) { struct id3_tag *tag; id3_byte_t *mem = 0; tag = id3_tag_new(); if (tag) { id3_byte_t const *end; id3_length_t size; parse_header(&ptr, &tag->version, &tag->flags, &size); tag->paddedsize = 10 + size; if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) && ID3_TAG_VERSION_MAJOR(tag->version) < 4) { mem = malloc(size); if (mem == 0) goto fail; memcpy(mem, ptr, size); size = id3_util_deunsynchronise(mem, size); ptr = mem; } end = ptr + size; if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) { switch (ID3_TAG_VERSION_MAJOR(tag->version)) { case 2: goto fail; case 3: { id3_byte_t const *ehptr, *ehend; id3_length_t ehsize; enum { EH_FLAG_CRC = 0x8000 /* CRC data present */ }; if (end - ptr < 4) goto fail; ehsize = id3_parse_uint(&ptr, 4); if (ehsize > end - ptr) goto fail; ehptr = ptr; ehend = ptr + ehsize; ptr = ehend; if (ehend - ehptr >= 6) { int ehflags; id3_length_t padsize; ehflags = id3_parse_uint(&ehptr, 2); padsize = id3_parse_uint(&ehptr, 4); if (padsize > end - ptr) goto fail; end -= padsize; if (ehflags & EH_FLAG_CRC) { unsigned long crc; if (ehend - ehptr < 4) goto fail; crc = id3_parse_uint(&ehptr, 4); if (crc != id3_crc_compute(ptr, end - ptr)) goto fail; tag->extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; } } } break; case 4: { id3_byte_t const *ehptr, *ehend; id3_length_t ehsize; unsigned int bytes; if (end - ptr < 4) goto fail; ehptr = ptr; ehsize = id3_parse_syncsafe(&ptr, 4); if (ehsize < 6 || ehsize > end - ehptr) goto fail; ehend = ehptr + ehsize; bytes = id3_parse_uint(&ptr, 1); if (bytes < 1 || bytes > ehend - ptr) goto fail; ehptr = ptr + bytes; /* verify extended header size */ { id3_byte_t const *flagsptr = ptr, *dataptr = ehptr; unsigned int datalen; int ehflags; while (bytes--) { for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags; ehflags = (ehflags << 1) & 0xff) { if (ehflags & 0x80) { if (dataptr == ehend) goto fail; datalen = id3_parse_uint(&dataptr, 1); if (datalen > 0x7f || datalen > ehend - dataptr) goto fail; dataptr += datalen; } } } } tag->extendedflags = id3_parse_uint(&ptr, 1); ptr = ehend; if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) { bytes = id3_parse_uint(&ehptr, 1); ehptr += bytes; } if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { unsigned long crc; bytes = id3_parse_uint(&ehptr, 1); if (bytes < 5) goto fail; crc = id3_parse_syncsafe(&ehptr, 5); ehptr += bytes - 5; if (crc != id3_crc_compute(ptr, end - ptr)) goto fail; } if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { bytes = id3_parse_uint(&ehptr, 1); if (bytes < 1) goto fail; tag->restrictions = id3_parse_uint(&ehptr, 1); ehptr += bytes - 1; } } break; } } /* frames */ while (ptr < end) { struct id3_frame *frame; if (*ptr == 0) break; /* padding */ frame = id3_frame_parse(&ptr, end - ptr, tag->version); if (frame == 0 || id3_tag_attachframe(tag, frame) == -1) goto fail; } if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 && id3_compat_fixup(tag) == -1) goto fail; } if (0) { fail: id3_tag_delete(tag); tag = 0; } if (mem) free(mem); return tag; }
int BarFlyID3AddCover(struct id3_tag* tag, uint8_t const* cover_art, size_t cover_size, BarSettings_t const* settings) { /* * http://flac.sourceforge.net/api/group__flac__format.html#ga113 */ int const PICTURE_TYPE_FRONT_COVER = 3; char const BAR_FLY_ID3_FRAME_PICTURE[] = "APIC"; int exit_status = 0; int status; struct id3_frame* frame = NULL; union id3_field* field; int index; char* mime_type; assert(tag != NULL); assert(cover_art != NULL); assert(settings != NULL); /* * Get a new picture frame. */ frame = id3_frame_new(BAR_FLY_ID3_FRAME_PICTURE); if (frame == NULL) { BarUiMsg(settings, MSG_ERR, "Failed to create new frame (type = %s).\n", BAR_FLY_ID3_FRAME_PICTURE); goto error; } /* * Go through all the frame fields setting the mime type, image type, and * the image data. */ index = 0; field = id3_frame_field(frame, index); while (field != NULL) { switch (id3_field_type(field)) { /* * Set the cover art mime type. */ case (ID3_FIELD_TYPE_LATIN1): if ((cover_art[0] == 0xFF) && (cover_art[1] == 0xD8)) { mime_type = "image/jpeg"; } else if ((cover_art[0] == 0x89) && (cover_art[1] == 0x50) && (cover_art[2] == 0x4E) && (cover_art[3] == 0x47) && (cover_art[4] == 0x0D) && (cover_art[5] == 0x0A) && (cover_art[6] == 0x1A) && (cover_art[7] == 0x0A)) { mime_type = "image/png"; } else { mime_type = NULL; } id3_field_setlatin1(field, (id3_latin1_t const*)mime_type); break; /* * Designate this as the front cover. */ case (ID3_FIELD_TYPE_INT8): id3_field_setint(field, PICTURE_TYPE_FRONT_COVER); break; /* * Set the image data. */ case (ID3_FIELD_TYPE_BINARYDATA): id3_field_setbinarydata(field, cover_art, cover_size); break; default: break; } index++; field = id3_frame_field(frame, index); } /* * Attach the frame to the tag. */ status = id3_tag_attachframe(tag, frame); if (status != 0) { BarUiMsg(settings, MSG_ERR, "Failed to attach cover art frame.\n"); goto error; } goto end; error: if (frame != NULL) { id3_frame_delete(frame); } exit_status = -1; end: return exit_status; }
int BarFlyID3AddFrame(struct id3_tag* tag, char const* type, char const* value, BarSettings_t const* settings) { int exit_status = 0; int status; struct id3_frame* frame = NULL; union id3_field* field; id3_ucs4_t* ucs4 = NULL; int index; assert(tag != NULL); assert(type != NULL); assert(value != NULL); assert(settings != NULL); /* * Create the frame. */ frame = id3_frame_new(type); if (frame == NULL) { BarUiMsg(settings, MSG_ERR, "Failed to create new frame (type = %s).\n", type); goto error; } frame->flags &= ~ID3_FRAME_FLAG_FORMATFLAGS; /* * Get the string list field of the frame. */ index = 0; do { field = id3_frame_field(frame, index); index++; } while (id3_field_type(field) != ID3_FIELD_TYPE_STRINGLIST); assert(id3_field_type(field) == ID3_FIELD_TYPE_STRINGLIST); /* * Add the value as a string to the field. */ ucs4 = id3_latin1_ucs4duplicate((id3_latin1_t*)value); if (ucs4 == NULL) { BarUiMsg(settings, MSG_ERR, "Could not allocate memory.\n"); goto error; } status = id3_field_addstring(field, ucs4); if (status != 0) { BarUiMsg(settings, MSG_ERR, "Failed to set field value (value = %s).\n", value); goto error; } /* * Attach the frame to the tag. */ status = id3_tag_attachframe(tag, frame); if (status != 0) { BarUiMsg(settings, MSG_ERR, "Failed to attach frame (type = %s).\n", type); goto error; } goto end; error: if (frame != NULL) { id3_frame_delete(frame); } exit_status = -1; end: if (ucs4 != NULL) { free(ucs4); } return exit_status; }
static context * context_create(const char *filename) { context *node = (context *) malloc(sizeof(context)); context *ptr, *last; int last_id = INT_MAX; node->refcount = 1; { struct id3_file *file; struct id3_tag *tag; unsigned int i; file = id3_file_open(filename, ID3_FILE_MODE_READONLY); if (!file) { fprintf(stderr, "Unable to open tagged file %s: %s\n", filename, strerror(errno)); goto fail_free; } tag = id3_file_tag(file); if (!tag) { fprintf(stderr, "Unable to find ID3v2 tags in file %s\n", filename); id3_file_close(file); goto fail_free; } node->tag = id3_tag_new(); for (i = 0; i < id3_tag_get_numframes(tag); i++) if (!strcmp(id3_frame_id(id3_tag_get_frame(tag, i)), "APIC")) id3_tag_attachframe(node->tag, id3_tag_get_frame(tag, i)); id3_file_close(file); } node->filename = strdup(filename); if (!id3_ctxs) { node->id = 1; node->next = NULL; id3_ctxs = node; return node; } ptr = id3_ctxs; last = NULL; while (UNLIKELY(ptr && (ptr->id + 1) >= last_id)) { last_id = ptr->id; last = ptr; ptr = ptr->next; } /* Paranoid! this can occur only if there are INT_MAX contexts :) */ if (UNLIKELY(!ptr)) { fprintf(stderr, "Too many open ID3 contexts\n"); goto fail_close; } node->id = ptr->id + 1; if (UNLIKELY(! !last)) { node->next = last->next; last->next = node; } else { node->next = id3_ctxs; id3_ctxs = node; } return node; fail_close: free(node->filename); id3_tag_delete(node->tag); fail_free: free(node); return NULL; }
// returns buffer len; caller frees int Tags::ExportID3(char **buffer, bool *endOfFile) { #ifdef USE_LIBID3TAG struct id3_tag *tp = id3_tag_new(); if (mTitle != wxT("")) id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_TITLE, mTitle.mb_str())); if (mArtist != wxT("")) id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_ARTIST, mArtist.mb_str())); if (mAlbum != wxT("")) id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_ALBUM, mAlbum.mb_str())); if (mYear != wxT("")) id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_YEAR, mYear.mb_str())); if (mComments != wxT("")) id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_COMMENT, mComments.mb_str())); if (mTrackNum >= 0) { wxString trackNumStr; trackNumStr.Printf(wxT("%d"), mTrackNum); id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_TRACK, trackNumStr.mb_str())); } if (mGenre >= 0) { if (mID3V2) { wxString genreStr = GetGenreNum(mGenre); id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_GENRE, genreStr.mb_str())); } else { wxString genreStr; genreStr.Printf(wxT("%d"), mGenre); id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_GENRE, genreStr.mb_str())); } } if (mID3V2) { tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression // If this version of libid3tag supports it, use v2.3 ID3 // tags instead of the newer, but less well supported, v2.4 // that libid3tag uses by default. #ifdef ID3_TAG_OPTION_ID3V2_3 tp->options |= ID3_TAG_OPTION_ID3V2_3; #endif *endOfFile = false; } else { tp->options |= ID3_TAG_OPTION_ID3V1; *endOfFile = true; } id3_length_t len; len = id3_tag_render(tp, 0); *buffer = (char *)malloc(len); len = id3_tag_render(tp, (id3_byte_t *)*buffer); id3_tag_delete(tp); return len; #else //ifdef USE_LIBID3TAG return 0; #endif }
/* * 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; }