int id3tag_write_v1(lame_global_flags * gfp) { lame_internal_flags *const gfc = gfp->internal_flags; size_t i, n, m; unsigned char tag[128]; m = sizeof(tag); n = lame_get_id3v1_tag(gfp, tag, m); if (n > m) { return 0; } /* write tag directly into bitstream at current position */ for (i = 0; i < n; ++i) { add_dummy_byte(gfc, tag[i], 1); } return (int) n; /* ok, tag has fixed size of 128 bytes, well below 2GB */ }
int id3tag_write_v2(lame_global_flags * gfp) { lame_internal_flags *gfc = gfp->internal_flags; #if 0 debug_tag_spec_flags(gfc, "write v2"); #endif if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) { return 0; } if (test_tag_spec_flags(gfc, CHANGED_FLAG)) { unsigned char *tag = 0; size_t tag_size, n; n = lame_get_id3v2_tag(gfp, 0, 0); tag = malloc(n); if (tag == 0) { return -1; } tag_size = lame_get_id3v2_tag(gfp, tag, n); if (tag_size > n) { free(tag); return -1; } else { size_t i; /* write tag directly into bitstream at current position */ for (i = 0; i < tag_size; ++i) { add_dummy_byte(gfc, tag[i], 1); } } free(tag); return (int) tag_size; /* ok, tag should not exceed 2GB */ } return 0; }
int id3tag_write_v2(lame_global_flags *gfp) { lame_internal_flags *gfc = gfp->internal_flags; if ((gfc->tag_spec.flags & CHANGED_FLAG) && !(gfc->tag_spec.flags & V1_ONLY_FLAG)) { /* calculate length of four fields which may not fit in verion 1 tag */ size_t title_length = gfc->tag_spec.title ? strlen(gfc->tag_spec.title) : 0; size_t artist_length = gfc->tag_spec.artist ? strlen(gfc->tag_spec.artist) : 0; size_t album_length = gfc->tag_spec.album ? strlen(gfc->tag_spec.album) : 0; size_t comment_length = gfc->tag_spec.comment ? strlen(gfc->tag_spec.comment) : 0; /* write tag if explicitly requested or if fields overflow */ if ((gfc->tag_spec.flags & (ADD_V2_FLAG | V2_ONLY_FLAG)) || (title_length > 30) || (artist_length > 30) || (album_length > 30) || (comment_length > 30) || (gfc->tag_spec.track && (comment_length > 28))) { size_t tag_size; char year[5]; size_t year_length; char track[3]; size_t track_length; char genre[6]; size_t genre_length; unsigned char *tag; unsigned char *p; size_t adjusted_tag_size; unsigned int index; /* calulate size of tag starting with 10-byte tag header */ tag_size = 10; if (title_length) { /* add 10-byte frame header, 1 encoding descriptor byte ... */ tag_size += 11 + title_length; } if (artist_length) { tag_size += 11 + artist_length; } if (album_length) { tag_size += 11 + album_length; } if (gfc->tag_spec.year) { year_length = sprintf(year, "%d", gfc->tag_spec.year); tag_size += 11 + year_length; } else { year_length = 0; } if (comment_length) { /* add 10-byte frame header, 1 encoding descriptor byte, * 3-byte language descriptor, 1 content descriptor byte ... */ tag_size += 15 + comment_length; } if (gfc->tag_spec.track) { track_length = sprintf(track, "%d", gfc->tag_spec.track); tag_size += 11 + track_length; } else { track_length = 0; } if (gfc->tag_spec.genre != GENRE_NUM_UNKNOWN) { genre_length = sprintf(genre, "(%d)", gfc->tag_spec.genre); tag_size += 11 + genre_length; } else { genre_length = 0; } if (gfc->tag_spec.flags & PAD_V2_FLAG) { /* add 128 bytes of padding */ tag_size += 128; } tag = (unsigned char *)malloc(tag_size); if (!tag) { return -1; } p = tag; /* set tag header starting with file identifier */ *p++ = 'I'; *p++ = 'D'; *p++ = '3'; /* set version number word */ *p++ = 3; *p++ = 0; /* clear flags byte */ *p++ = 0; /* calculate and set tag size = total size - header size */ adjusted_tag_size = tag_size - 10; /* encode adjusted size into four bytes where most significant * bit is clear in each byte, for 28-bit total */ *p++ = (adjusted_tag_size >> 21) & 0x7fu; *p++ = (adjusted_tag_size >> 14) & 0x7fu; *p++ = (adjusted_tag_size >> 7) & 0x7fu; *p++ = adjusted_tag_size & 0x7fu; /* * NOTE: The remainder of the tag (frames and padding, if any) * are not "unsynchronized" to prevent false MPEG audio headers * from appearing in the bitstream. Why? Well, most players * and utilities know how to skip the ID3 version 2 tag by now * even if they don't read its contents, and it's actually * very unlikely that such a false "sync" pattern would occur * in just the simple text frames added here. */ /* set each frame in tag */ p = set_frame(p, TITLE_FRAME_ID, gfc->tag_spec.title, title_length); p = set_frame(p, ARTIST_FRAME_ID, gfc->tag_spec.artist, artist_length); p = set_frame(p, ALBUM_FRAME_ID, gfc->tag_spec.album, album_length); p = set_frame(p, YEAR_FRAME_ID, year, year_length); p = set_frame(p, COMMENT_FRAME_ID, gfc->tag_spec.comment, comment_length); p = set_frame(p, TRACK_FRAME_ID, track, track_length); p = set_frame(p, GENRE_FRAME_ID, genre, genre_length); /* clear any padding bytes */ memset(p, 0, tag_size - (p - tag)); /* write tag directly into bitstream at current position */ for (index = 0; index < tag_size; ++index) { add_dummy_byte(gfp, tag[index]); } free(tag); return tag_size; }