1 /* libFLAC - Free Lossless Audio Codec library
2 * Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008,2009 Josh Coalson
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include "private/metadata.h"
40 #include "private/memory.h"
42 #include "FLAC/assert.h"
43 #include "share/alloc.h"
45 /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
46 #define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
49 /****************************************************************************
53 ***************************************************************************/
56 * from = NULL && bytes = 0
58 * from != NULL && bytes > 0
61 * malloc error leaves 'to' unchanged
63 static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
65 FLAC__ASSERT(0 != to);
66 if(bytes > 0 && 0 != from) {
68 if(0 == (x = safe_malloc_(bytes)))
70 memcpy(x, from, bytes);
74 FLAC__ASSERT(0 == from);
75 FLAC__ASSERT(bytes == 0);
82 /* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */
83 static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
86 FLAC__ASSERT(0 != to);
87 if(copy_bytes_(©, from, bytes)) {
98 /* reallocate entry to 1 byte larger and add a terminating NUL */
99 /* realloc() failure leaves entry unchanged */
100 static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
102 FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1);
112 /* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
113 * unchanged if malloc fails, free()ing the original '*to' if it
114 * succeeds and the original '*to' was not NULL
116 static FLAC__bool copy_cstring_(char **to, const char *from)
118 char *copy = strdup(from);
130 static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
132 to->length = from->length;
133 if(0 == from->entry) {
134 FLAC__ASSERT(from->length == 0);
139 FLAC__ASSERT(from->length > 0);
140 if(0 == (x = safe_malloc_add_2op_(from->length, /*+*/1)))
142 memcpy(x, from->entry, from->length);
143 x[from->length] = '\0';
149 static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
151 memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
152 if(0 == from->indices) {
153 FLAC__ASSERT(from->num_indices == 0);
156 FLAC__StreamMetadata_CueSheet_Index *x;
157 FLAC__ASSERT(from->num_indices > 0);
158 if(0 == (x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))))
160 memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
166 static void seektable_calculate_length_(FLAC__StreamMetadata *object)
168 FLAC__ASSERT(0 != object);
169 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
171 object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
174 static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
176 FLAC__StreamMetadata_SeekPoint *object_array;
178 FLAC__ASSERT(num_points > 0);
180 object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
182 if(0 != object_array) {
184 for(i = 0; i < num_points; i++) {
185 object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
186 object_array[i].stream_offset = 0;
187 object_array[i].frame_samples = 0;
194 static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
198 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
200 object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
201 object->length += object->data.vorbis_comment.vendor_string.length;
202 object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
203 for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
204 object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
205 object->length += object->data.vorbis_comment.comments[i].length;
209 static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments)
211 FLAC__ASSERT(num_comments > 0);
213 return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
216 static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
220 FLAC__ASSERT(0 != object_array && num_comments > 0);
222 for(i = 0; i < num_comments; i++)
223 if(0 != object_array[i].entry)
224 free(object_array[i].entry);
226 if(0 != object_array)
230 static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
232 FLAC__StreamMetadata_VorbisComment_Entry *return_array;
234 FLAC__ASSERT(0 != object_array);
235 FLAC__ASSERT(num_comments > 0);
237 return_array = vorbiscomment_entry_array_new_(num_comments);
239 if(0 != return_array) {
242 for(i = 0; i < num_comments; i++) {
243 if(!copy_vcentry_(return_array+i, object_array+i)) {
244 vorbiscomment_entry_array_delete_(return_array, num_comments);
253 static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
257 FLAC__ASSERT(0 != object);
258 FLAC__ASSERT(0 != dest);
259 FLAC__ASSERT(0 != src);
260 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
261 FLAC__ASSERT((0 != src->entry && src->length > 0) || (0 == src->entry && src->length == 0));
265 if(0 != src->entry && src->length > 0) {
267 /* do the copy first so that if we fail we leave the dest object untouched */
268 if(!copy_vcentry_(dest, src))
272 /* we have to make sure that the string we're taking over is null-terminated */
275 * Stripping the const from src->entry is OK since we're taking
276 * ownership of the pointer. This is a hack around a deficiency
277 * in the API where the same function is used for 'copy' and
278 * 'own', but the source entry is a const pointer. If we were
279 * precise, the 'own' flavor would be a separate function with a
280 * non-const source pointer. But it's not, so we hack away.
282 if(!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
288 /* the src is null */
295 vorbiscomment_calculate_length_(object);
299 static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
303 FLAC__ASSERT(0 != object);
304 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
305 FLAC__ASSERT(0 != field_name);
307 for(i = offset; i < object->data.vorbis_comment.num_comments; i++) {
308 if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
315 static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
319 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
322 FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
323 FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
324 FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
325 FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
326 FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
329 object->length += object->data.cue_sheet.num_tracks * (
330 FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
331 FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
332 FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
333 FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
334 FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
335 FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
336 FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
339 for(i = 0; i < object->data.cue_sheet.num_tracks; i++) {
340 object->length += object->data.cue_sheet.tracks[i].num_indices * (
341 FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
342 FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
343 FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
348 static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
350 FLAC__ASSERT(num_indices > 0);
352 return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
355 static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
357 FLAC__ASSERT(num_tracks > 0);
359 return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
362 static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
366 FLAC__ASSERT(0 != object_array && num_tracks > 0);
368 for(i = 0; i < num_tracks; i++) {
369 if(0 != object_array[i].indices) {
370 FLAC__ASSERT(object_array[i].num_indices > 0);
371 free(object_array[i].indices);
375 if(0 != object_array)
379 static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
381 FLAC__StreamMetadata_CueSheet_Track *return_array;
383 FLAC__ASSERT(0 != object_array);
384 FLAC__ASSERT(num_tracks > 0);
386 return_array = cuesheet_track_array_new_(num_tracks);
388 if(0 != return_array) {
391 for(i = 0; i < num_tracks; i++) {
392 if(!copy_track_(return_array+i, object_array+i)) {
393 cuesheet_track_array_delete_(return_array, num_tracks);
402 static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
404 FLAC__StreamMetadata_CueSheet_Index *save;
406 FLAC__ASSERT(0 != object);
407 FLAC__ASSERT(0 != dest);
408 FLAC__ASSERT(0 != src);
409 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
410 FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0));
412 save = dest->indices;
414 /* do the copy first so that if we fail we leave the object untouched */
416 if(!copy_track_(dest, src))
426 cuesheet_calculate_length_(object);
431 /****************************************************************************
433 * Metadata object routines
435 ***************************************************************************/
437 FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
439 FLAC__StreamMetadata *object;
441 if(type > FLAC__MAX_METADATA_TYPE_CODE)
444 object = calloc(1, sizeof(FLAC__StreamMetadata));
446 object->is_last = false;
449 case FLAC__METADATA_TYPE_STREAMINFO:
450 object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
452 case FLAC__METADATA_TYPE_PADDING:
453 /* calloc() took care of this for us:
457 case FLAC__METADATA_TYPE_APPLICATION:
458 object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
459 /* calloc() took care of this for us:
460 object->data.application.data = 0;
463 case FLAC__METADATA_TYPE_SEEKTABLE:
464 /* calloc() took care of this for us:
466 object->data.seek_table.num_points = 0;
467 object->data.seek_table.points = 0;
470 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
471 object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
472 if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
476 vorbiscomment_calculate_length_(object);
478 case FLAC__METADATA_TYPE_CUESHEET:
479 cuesheet_calculate_length_(object);
481 case FLAC__METADATA_TYPE_PICTURE:
483 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
484 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
485 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
486 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
487 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
488 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
489 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
490 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
493 object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
494 object->data.picture.mime_type = 0;
495 object->data.picture.description = 0;
496 /* calloc() took care of this for us:
497 object->data.picture.width = 0;
498 object->data.picture.height = 0;
499 object->data.picture.depth = 0;
500 object->data.picture.colors = 0;
501 object->data.picture.data_length = 0;
502 object->data.picture.data = 0;
504 /* now initialize mime_type and description with empty strings to make things easier on the client */
505 if(!copy_cstring_(&object->data.picture.mime_type, "")) {
509 if(!copy_cstring_((char**)(&object->data.picture.description), "")) {
510 if(object->data.picture.mime_type)
511 free(object->data.picture.mime_type);
517 /* calloc() took care of this for us:
519 object->data.unknown.data = 0;
528 FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
530 FLAC__StreamMetadata *to;
532 FLAC__ASSERT(0 != object);
534 if(0 != (to = FLAC__metadata_object_new(object->type))) {
535 to->is_last = object->is_last;
536 to->type = object->type;
537 to->length = object->length;
539 case FLAC__METADATA_TYPE_STREAMINFO:
540 memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
542 case FLAC__METADATA_TYPE_PADDING:
544 case FLAC__METADATA_TYPE_APPLICATION:
545 if(to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */
546 FLAC__metadata_object_delete(to);
549 memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
550 if(!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
551 FLAC__metadata_object_delete(to);
555 case FLAC__METADATA_TYPE_SEEKTABLE:
556 to->data.seek_table.num_points = object->data.seek_table.num_points;
557 if(to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */
558 FLAC__metadata_object_delete(to);
561 if(!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) {
562 FLAC__metadata_object_delete(to);
566 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
567 if(0 != to->data.vorbis_comment.vendor_string.entry) {
568 free(to->data.vorbis_comment.vendor_string.entry);
569 to->data.vorbis_comment.vendor_string.entry = 0;
571 if(!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
572 FLAC__metadata_object_delete(to);
575 if(object->data.vorbis_comment.num_comments == 0) {
576 FLAC__ASSERT(0 == object->data.vorbis_comment.comments);
577 to->data.vorbis_comment.comments = 0;
580 FLAC__ASSERT(0 != object->data.vorbis_comment.comments);
581 to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
582 if(0 == to->data.vorbis_comment.comments) {
583 FLAC__metadata_object_delete(to);
587 to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
589 case FLAC__METADATA_TYPE_CUESHEET:
590 memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
591 if(object->data.cue_sheet.num_tracks == 0) {
592 FLAC__ASSERT(0 == object->data.cue_sheet.tracks);
595 FLAC__ASSERT(0 != object->data.cue_sheet.tracks);
596 to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
597 if(0 == to->data.cue_sheet.tracks) {
598 FLAC__metadata_object_delete(to);
603 case FLAC__METADATA_TYPE_PICTURE:
604 to->data.picture.type = object->data.picture.type;
605 if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
606 FLAC__metadata_object_delete(to);
609 if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
610 FLAC__metadata_object_delete(to);
613 to->data.picture.width = object->data.picture.width;
614 to->data.picture.height = object->data.picture.height;
615 to->data.picture.depth = object->data.picture.depth;
616 to->data.picture.colors = object->data.picture.colors;
617 to->data.picture.data_length = object->data.picture.data_length;
618 if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
619 FLAC__metadata_object_delete(to);
624 if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
625 FLAC__metadata_object_delete(to);
635 void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
637 FLAC__ASSERT(0 != object);
639 switch(object->type) {
640 case FLAC__METADATA_TYPE_STREAMINFO:
641 case FLAC__METADATA_TYPE_PADDING:
643 case FLAC__METADATA_TYPE_APPLICATION:
644 if(0 != object->data.application.data) {
645 free(object->data.application.data);
646 object->data.application.data = 0;
649 case FLAC__METADATA_TYPE_SEEKTABLE:
650 if(0 != object->data.seek_table.points) {
651 free(object->data.seek_table.points);
652 object->data.seek_table.points = 0;
655 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
656 if(0 != object->data.vorbis_comment.vendor_string.entry) {
657 free(object->data.vorbis_comment.vendor_string.entry);
658 object->data.vorbis_comment.vendor_string.entry = 0;
660 if(0 != object->data.vorbis_comment.comments) {
661 FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
662 vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
665 case FLAC__METADATA_TYPE_CUESHEET:
666 if(0 != object->data.cue_sheet.tracks) {
667 FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
668 cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
671 case FLAC__METADATA_TYPE_PICTURE:
672 if(0 != object->data.picture.mime_type) {
673 free(object->data.picture.mime_type);
674 object->data.picture.mime_type = 0;
676 if(0 != object->data.picture.description) {
677 free(object->data.picture.description);
678 object->data.picture.description = 0;
680 if(0 != object->data.picture.data) {
681 free(object->data.picture.data);
682 object->data.picture.data = 0;
686 if(0 != object->data.unknown.data) {
687 free(object->data.unknown.data);
688 object->data.unknown.data = 0;
694 FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
696 FLAC__metadata_object_delete_data(object);
700 static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
702 if(block1->min_blocksize != block2->min_blocksize)
704 if(block1->max_blocksize != block2->max_blocksize)
706 if(block1->min_framesize != block2->min_framesize)
708 if(block1->max_framesize != block2->max_framesize)
710 if(block1->sample_rate != block2->sample_rate)
712 if(block1->channels != block2->channels)
714 if(block1->bits_per_sample != block2->bits_per_sample)
716 if(block1->total_samples != block2->total_samples)
718 if(0 != memcmp(block1->md5sum, block2->md5sum, 16))
723 static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, unsigned block_length)
725 FLAC__ASSERT(0 != block1);
726 FLAC__ASSERT(0 != block2);
727 FLAC__ASSERT(block_length >= sizeof(block1->id));
729 if(0 != memcmp(block1->id, block2->id, sizeof(block1->id)))
731 if(0 != block1->data && 0 != block2->data)
732 return 0 == memcmp(block1->data, block2->data, block_length - sizeof(block1->id));
734 return block1->data == block2->data;
737 static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
741 FLAC__ASSERT(0 != block1);
742 FLAC__ASSERT(0 != block2);
744 if(block1->num_points != block2->num_points)
747 if(0 != block1->points && 0 != block2->points) {
748 for(i = 0; i < block1->num_points; i++) {
749 if(block1->points[i].sample_number != block2->points[i].sample_number)
751 if(block1->points[i].stream_offset != block2->points[i].stream_offset)
753 if(block1->points[i].frame_samples != block2->points[i].frame_samples)
759 return block1->points == block2->points;
762 static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
766 if(block1->vendor_string.length != block2->vendor_string.length)
769 if(0 != block1->vendor_string.entry && 0 != block2->vendor_string.entry) {
770 if(0 != memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length))
773 else if(block1->vendor_string.entry != block2->vendor_string.entry)
776 if(block1->num_comments != block2->num_comments)
779 for(i = 0; i < block1->num_comments; i++) {
780 if(0 != block1->comments[i].entry && 0 != block2->comments[i].entry) {
781 if(0 != memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length))
784 else if(block1->comments[i].entry != block2->comments[i].entry)
790 static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
794 if(0 != strcmp(block1->media_catalog_number, block2->media_catalog_number))
797 if(block1->lead_in != block2->lead_in)
800 if(block1->is_cd != block2->is_cd)
803 if(block1->num_tracks != block2->num_tracks)
806 if(0 != block1->tracks && 0 != block2->tracks) {
807 FLAC__ASSERT(block1->num_tracks > 0);
808 for(i = 0; i < block1->num_tracks; i++) {
809 if(block1->tracks[i].offset != block2->tracks[i].offset)
811 if(block1->tracks[i].number != block2->tracks[i].number)
813 if(0 != memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)))
815 if(block1->tracks[i].type != block2->tracks[i].type)
817 if(block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
819 if(block1->tracks[i].num_indices != block2->tracks[i].num_indices)
821 if(0 != block1->tracks[i].indices && 0 != block2->tracks[i].indices) {
822 FLAC__ASSERT(block1->tracks[i].num_indices > 0);
823 for(j = 0; j < block1->tracks[i].num_indices; j++) {
824 if(block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
826 if(block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
830 else if(block1->tracks[i].indices != block2->tracks[i].indices)
834 else if(block1->tracks != block2->tracks)
839 static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
841 if(block1->type != block2->type)
843 if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type)))
845 if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description)))
847 if(block1->width != block2->width)
849 if(block1->height != block2->height)
851 if(block1->depth != block2->depth)
853 if(block1->colors != block2->colors)
855 if(block1->data_length != block2->data_length)
857 if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length)))
862 static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length)
864 FLAC__ASSERT(0 != block1);
865 FLAC__ASSERT(0 != block2);
867 if(0 != block1->data && 0 != block2->data)
868 return 0 == memcmp(block1->data, block2->data, block_length);
870 return block1->data == block2->data;
873 FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
875 FLAC__ASSERT(0 != block1);
876 FLAC__ASSERT(0 != block2);
878 if(block1->type != block2->type) {
881 if(block1->is_last != block2->is_last) {
884 if(block1->length != block2->length) {
887 switch(block1->type) {
888 case FLAC__METADATA_TYPE_STREAMINFO:
889 return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
890 case FLAC__METADATA_TYPE_PADDING:
891 return true; /* we don't compare the padding guts */
892 case FLAC__METADATA_TYPE_APPLICATION:
893 return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
894 case FLAC__METADATA_TYPE_SEEKTABLE:
895 return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
896 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
897 return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
898 case FLAC__METADATA_TYPE_CUESHEET:
899 return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
900 case FLAC__METADATA_TYPE_PICTURE:
901 return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
903 return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
907 FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy)
911 FLAC__ASSERT(0 != object);
912 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
913 FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
915 save = object->data.application.data;
917 /* do the copy first so that if we fail we leave the object untouched */
919 if(!copy_bytes_(&object->data.application.data, data, length))
923 object->data.application.data = data;
929 object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
933 FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points)
935 FLAC__ASSERT(0 != object);
936 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
938 if(0 == object->data.seek_table.points) {
939 FLAC__ASSERT(object->data.seek_table.num_points == 0);
940 if(0 == new_num_points)
942 else if(0 == (object->data.seek_table.points = seekpoint_array_new_(new_num_points)))
946 const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
947 const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
950 if(new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint))
953 FLAC__ASSERT(object->data.seek_table.num_points > 0);
956 free(object->data.seek_table.points);
957 object->data.seek_table.points = 0;
959 else if(0 == (object->data.seek_table.points = realloc(object->data.seek_table.points, new_size)))
962 /* if growing, set new elements to placeholders */
963 if(new_size > old_size) {
965 for(i = object->data.seek_table.num_points; i < new_num_points; i++) {
966 object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
967 object->data.seek_table.points[i].stream_offset = 0;
968 object->data.seek_table.points[i].frame_samples = 0;
973 object->data.seek_table.num_points = new_num_points;
975 seektable_calculate_length_(object);
979 FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
981 FLAC__ASSERT(0 != object);
982 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
983 FLAC__ASSERT(point_num < object->data.seek_table.num_points);
985 object->data.seek_table.points[point_num] = point;
988 FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
992 FLAC__ASSERT(0 != object);
993 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
994 FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
996 if(!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
999 /* move all points >= point_num forward one space */
1000 for(i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
1001 object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
1003 FLAC__metadata_object_seektable_set_point(object, point_num, point);
1004 seektable_calculate_length_(object);
1008 FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num)
1012 FLAC__ASSERT(0 != object);
1013 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1014 FLAC__ASSERT(point_num < object->data.seek_table.num_points);
1016 /* move all points > point_num backward one space */
1017 for(i = point_num; i < object->data.seek_table.num_points-1; i++)
1018 object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
1020 return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
1023 FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
1025 FLAC__ASSERT(0 != object);
1026 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1028 return FLAC__format_seektable_is_legal(&object->data.seek_table);
1031 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num)
1033 FLAC__ASSERT(0 != object);
1034 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1037 /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
1038 return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
1043 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
1045 FLAC__StreamMetadata_SeekTable *seek_table;
1047 FLAC__ASSERT(0 != object);
1048 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1050 seek_table = &object->data.seek_table;
1052 if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
1055 seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
1056 seek_table->points[seek_table->num_points - 1].stream_offset = 0;
1057 seek_table->points[seek_table->num_points - 1].frame_samples = 0;
1062 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num)
1064 FLAC__ASSERT(0 != object);
1065 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1066 FLAC__ASSERT(0 != sample_numbers || num == 0);
1069 FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
1072 i = seek_table->num_points;
1074 if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
1077 for(j = 0; j < num; i++, j++) {
1078 seek_table->points[i].sample_number = sample_numbers[j];
1079 seek_table->points[i].stream_offset = 0;
1080 seek_table->points[i].frame_samples = 0;
1087 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples)
1089 FLAC__ASSERT(0 != object);
1090 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1091 FLAC__ASSERT(total_samples > 0);
1093 if(num > 0 && total_samples > 0) {
1094 FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
1097 i = seek_table->num_points;
1099 if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
1102 for(j = 0; j < num; i++, j++) {
1103 seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
1104 seek_table->points[i].stream_offset = 0;
1105 seek_table->points[i].frame_samples = 0;
1112 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples)
1114 FLAC__ASSERT(0 != object);
1115 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1116 FLAC__ASSERT(samples > 0);
1117 FLAC__ASSERT(total_samples > 0);
1119 if(samples > 0 && total_samples > 0) {
1120 FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
1122 FLAC__uint64 num, sample;
1124 num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
1125 /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
1126 if(total_samples % samples == 0)
1129 i = seek_table->num_points;
1131 if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (unsigned)num))
1135 for(j = 0; j < num; i++, j++, sample += samples) {
1136 seek_table->points[i].sample_number = sample;
1137 seek_table->points[i].stream_offset = 0;
1138 seek_table->points[i].frame_samples = 0;
1145 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
1149 FLAC__ASSERT(0 != object);
1150 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
1152 unique = FLAC__format_seektable_sort(&object->data.seek_table);
1154 return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
1157 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
1159 if(!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
1161 return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
1164 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments)
1166 FLAC__ASSERT(0 != object);
1167 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
1169 if(0 == object->data.vorbis_comment.comments) {
1170 FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
1171 if(0 == new_num_comments)
1173 else if(0 == (object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)))
1177 const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
1178 const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
1180 /* overflow check */
1181 if(new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry))
1184 FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
1186 /* if shrinking, free the truncated entries */
1187 if(new_num_comments < object->data.vorbis_comment.num_comments) {
1189 for(i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
1190 if(0 != object->data.vorbis_comment.comments[i].entry)
1191 free(object->data.vorbis_comment.comments[i].entry);
1195 free(object->data.vorbis_comment.comments);
1196 object->data.vorbis_comment.comments = 0;
1198 else if(0 == (object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)))
1201 /* if growing, zero all the length/pointers of new elements */
1202 if(new_size > old_size)
1203 memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
1206 object->data.vorbis_comment.num_comments = new_num_comments;
1208 vorbiscomment_calculate_length_(object);
1212 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
1214 FLAC__ASSERT(0 != object);
1215 FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
1217 if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
1219 return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
1222 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
1224 FLAC__StreamMetadata_VorbisComment *vc;
1226 FLAC__ASSERT(0 != object);
1227 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
1228 FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
1230 if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
1233 vc = &object->data.vorbis_comment;
1235 if(!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
1238 /* move all comments >= comment_num forward one space */
1239 memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
1240 vc->comments[comment_num].length = 0;
1241 vc->comments[comment_num].entry = 0;
1243 return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
1246 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
1248 FLAC__ASSERT(0 != object);
1249 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
1250 return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
1253 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
1255 FLAC__ASSERT(0 != entry.entry && entry.length > 0);
1257 if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
1262 size_t field_name_length;
1263 const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
1265 FLAC__ASSERT(0 != eq);
1268 return false; /* double protection */
1270 field_name_length = eq-entry.entry;
1272 i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length);
1274 unsigned index = (unsigned)i;
1275 if(!FLAC__metadata_object_vorbiscomment_set_comment(object, index, entry, copy))
1277 entry = object->data.vorbis_comment.comments[index];
1278 index++; /* skip over replaced comment */
1279 if(all && index < object->data.vorbis_comment.num_comments) {
1280 i = vorbiscomment_find_entry_from_(object, index, (const char *)entry.entry, field_name_length);
1282 index = (unsigned)i;
1283 if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, index))
1285 if(index < object->data.vorbis_comment.num_comments)
1286 i = vorbiscomment_find_entry_from_(object, index, (const char *)entry.entry, field_name_length);
1294 return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
1298 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
1300 FLAC__StreamMetadata_VorbisComment *vc;
1302 FLAC__ASSERT(0 != object);
1303 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
1304 FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
1306 vc = &object->data.vorbis_comment;
1308 /* free the comment at comment_num */
1309 if(0 != vc->comments[comment_num].entry)
1310 free(vc->comments[comment_num].entry);
1312 /* move all comments > comment_num backward one space */
1313 memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
1314 vc->comments[vc->num_comments-1].length = 0;
1315 vc->comments[vc->num_comments-1].entry = 0;
1317 return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
1320 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
1322 FLAC__ASSERT(0 != entry);
1323 FLAC__ASSERT(0 != field_name);
1324 FLAC__ASSERT(0 != field_value);
1326 if(!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
1328 if(!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (unsigned)(-1)))
1332 const size_t nn = strlen(field_name);
1333 const size_t nv = strlen(field_value);
1334 entry->length = nn + 1 /*=*/ + nv;
1335 if(0 == (entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)))
1337 memcpy(entry->entry, field_name, nn);
1338 entry->entry[nn] = '=';
1339 memcpy(entry->entry+nn+1, field_value, nv);
1340 entry->entry[entry->length] = '\0';
1346 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
1348 FLAC__ASSERT(0 != entry.entry && entry.length > 0);
1349 FLAC__ASSERT(0 != field_name);
1350 FLAC__ASSERT(0 != field_value);
1352 if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
1356 const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
1357 const size_t nn = eq-entry.entry;
1358 const size_t nv = entry.length-nn-1; /* -1 for the '=' */
1359 FLAC__ASSERT(0 != eq);
1361 return false; /* double protection */
1362 if(0 == (*field_name = safe_malloc_add_2op_(nn, /*+*/1)))
1364 if(0 == (*field_value = safe_malloc_add_2op_(nv, /*+*/1))) {
1368 memcpy(*field_name, entry.entry, nn);
1369 memcpy(*field_value, entry.entry+nn+1, nv);
1370 (*field_name)[nn] = '\0';
1371 (*field_value)[nv] = '\0';
1377 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length)
1379 FLAC__ASSERT(0 != entry.entry && entry.length > 0);
1381 const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
1382 #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
1383 #define FLAC__STRNCASECMP strnicmp
1385 #define FLAC__STRNCASECMP strncasecmp
1387 return (0 != eq && (unsigned)(eq-entry.entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length));
1388 #undef FLAC__STRNCASECMP
1392 FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
1394 FLAC__ASSERT(0 != field_name);
1396 return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name));
1399 FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
1401 const unsigned field_name_length = strlen(field_name);
1404 FLAC__ASSERT(0 != object);
1405 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
1407 for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
1408 if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
1409 if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
1419 FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
1421 FLAC__bool ok = true;
1422 unsigned matching = 0;
1423 const unsigned field_name_length = strlen(field_name);
1426 FLAC__ASSERT(0 != object);
1427 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
1429 /* must delete from end to start otherwise it will interfere with our iteration */
1430 for(i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
1431 if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
1433 ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
1437 return ok? (int)matching : -1;
1440 FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
1442 return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
1445 FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
1447 FLAC__StreamMetadata_CueSheet_Track *to;
1449 FLAC__ASSERT(0 != object);
1451 if(0 != (to = FLAC__metadata_object_cuesheet_track_new())) {
1452 if(!copy_track_(to, object)) {
1453 FLAC__metadata_object_cuesheet_track_delete(to);
1461 void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
1463 FLAC__ASSERT(0 != object);
1465 if(0 != object->indices) {
1466 FLAC__ASSERT(object->num_indices > 0);
1467 free(object->indices);
1471 FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
1473 FLAC__metadata_object_cuesheet_track_delete_data(object);
1477 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
1479 FLAC__StreamMetadata_CueSheet_Track *track;
1480 FLAC__ASSERT(0 != object);
1481 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1482 FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
1484 track = &object->data.cue_sheet.tracks[track_num];
1486 if(0 == track->indices) {
1487 FLAC__ASSERT(track->num_indices == 0);
1488 if(0 == new_num_indices)
1490 else if(0 == (track->indices = cuesheet_track_index_array_new_(new_num_indices)))
1494 const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
1495 const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
1497 /* overflow check */
1498 if(new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index))
1501 FLAC__ASSERT(track->num_indices > 0);
1504 free(track->indices);
1507 else if(0 == (track->indices = realloc(track->indices, new_size)))
1510 /* if growing, zero all the lengths/pointers of new elements */
1511 if(new_size > old_size)
1512 memset(track->indices + track->num_indices, 0, new_size - old_size);
1515 track->num_indices = new_num_indices;
1517 cuesheet_calculate_length_(object);
1521 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index)
1523 FLAC__StreamMetadata_CueSheet_Track *track;
1525 FLAC__ASSERT(0 != object);
1526 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1527 FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
1528 FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
1530 track = &object->data.cue_sheet.tracks[track_num];
1532 if(!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
1535 /* move all indices >= index_num forward one space */
1536 memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
1538 track->indices[index_num] = index;
1539 cuesheet_calculate_length_(object);
1543 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
1545 FLAC__StreamMetadata_CueSheet_Index index;
1546 memset(&index, 0, sizeof(index));
1547 return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, index);
1550 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
1552 FLAC__StreamMetadata_CueSheet_Track *track;
1554 FLAC__ASSERT(0 != object);
1555 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1556 FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
1557 FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
1559 track = &object->data.cue_sheet.tracks[track_num];
1561 /* move all indices > index_num backward one space */
1562 memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
1564 FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
1565 cuesheet_calculate_length_(object);
1569 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
1571 FLAC__ASSERT(0 != object);
1572 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1574 if(0 == object->data.cue_sheet.tracks) {
1575 FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
1576 if(0 == new_num_tracks)
1578 else if(0 == (object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)))
1582 const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
1583 const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
1585 /* overflow check */
1586 if(new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track))
1589 FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
1591 /* if shrinking, free the truncated entries */
1592 if(new_num_tracks < object->data.cue_sheet.num_tracks) {
1594 for(i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
1595 if(0 != object->data.cue_sheet.tracks[i].indices)
1596 free(object->data.cue_sheet.tracks[i].indices);
1600 free(object->data.cue_sheet.tracks);
1601 object->data.cue_sheet.tracks = 0;
1603 else if(0 == (object->data.cue_sheet.tracks = realloc(object->data.cue_sheet.tracks, new_size)))
1606 /* if growing, zero all the lengths/pointers of new elements */
1607 if(new_size > old_size)
1608 memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
1611 object->data.cue_sheet.num_tracks = new_num_tracks;
1613 cuesheet_calculate_length_(object);
1617 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
1619 FLAC__ASSERT(0 != object);
1620 FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
1622 return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
1625 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
1627 FLAC__StreamMetadata_CueSheet *cs;
1629 FLAC__ASSERT(0 != object);
1630 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1631 FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
1633 cs = &object->data.cue_sheet;
1635 if(!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
1638 /* move all tracks >= track_num forward one space */
1639 memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
1640 cs->tracks[track_num].num_indices = 0;
1641 cs->tracks[track_num].indices = 0;
1643 return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
1646 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num)
1648 FLAC__StreamMetadata_CueSheet_Track track;
1649 memset(&track, 0, sizeof(track));
1650 return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
1653 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
1655 FLAC__StreamMetadata_CueSheet *cs;
1657 FLAC__ASSERT(0 != object);
1658 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1659 FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
1661 cs = &object->data.cue_sheet;
1663 /* free the track at track_num */
1664 if(0 != cs->tracks[track_num].indices)
1665 free(cs->tracks[track_num].indices);
1667 /* move all tracks > track_num backward one space */
1668 memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
1669 cs->tracks[cs->num_tracks-1].num_indices = 0;
1670 cs->tracks[cs->num_tracks-1].indices = 0;
1672 return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
1675 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
1677 FLAC__ASSERT(0 != object);
1678 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1680 return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
1683 static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track)
1685 if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
1687 else if (cs->tracks[track].indices[0].number == 1)
1688 return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
1689 else if (cs->tracks[track].num_indices < 2)
1691 else if (cs->tracks[track].indices[1].number == 1)
1692 return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
1697 static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
1707 /*@@@@add to tests*/
1708 FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
1710 const FLAC__StreamMetadata_CueSheet *cs;
1712 FLAC__ASSERT(0 != object);
1713 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
1715 cs = &object->data.cue_sheet;
1717 if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
1721 FLAC__uint32 i, length, sum = 0;
1722 for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
1723 sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
1724 length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
1726 return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
1730 FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
1733 size_t old_length, new_length;
1735 FLAC__ASSERT(0 != object);
1736 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
1737 FLAC__ASSERT(0 != mime_type);
1739 old = object->data.picture.mime_type;
1740 old_length = old? strlen(old) : 0;
1741 new_length = strlen(mime_type);
1743 /* do the copy first so that if we fail we leave the object untouched */
1745 if(new_length >= SIZE_MAX) /* overflow check */
1747 if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1))
1751 object->data.picture.mime_type = mime_type;
1757 object->length -= old_length;
1758 object->length += new_length;
1762 FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
1765 size_t old_length, new_length;
1767 FLAC__ASSERT(0 != object);
1768 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
1769 FLAC__ASSERT(0 != description);
1771 old = object->data.picture.description;
1772 old_length = old? strlen((const char *)old) : 0;
1773 new_length = strlen((const char *)description);
1775 /* do the copy first so that if we fail we leave the object untouched */
1777 if(new_length >= SIZE_MAX) /* overflow check */
1779 if(!copy_bytes_(&object->data.picture.description, description, new_length+1))
1783 object->data.picture.description = description;
1789 object->length -= old_length;
1790 object->length += new_length;
1794 FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
1798 FLAC__ASSERT(0 != object);
1799 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
1800 FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
1802 old = object->data.picture.data;
1804 /* do the copy first so that if we fail we leave the object untouched */
1806 if(!copy_bytes_(&object->data.picture.data, data, length))
1810 object->data.picture.data = data;
1816 object->length -= object->data.picture.data_length;
1817 object->data.picture.data_length = length;
1818 object->length += length;
1822 FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
1824 FLAC__ASSERT(0 != object);
1825 FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
1827 return FLAC__format_picture_is_legal(&object->data.picture, violation);