Home | History | Annotate | Download | only in libFLAC
      1 /* libFLAC - Free Lossless Audio Codec library
      2  * Copyright (C) 2001-2009  Josh Coalson
      3  * Copyright (C) 2011-2016  Xiph.Org Foundation
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * - Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *
     12  * - Redistributions in binary form must reproduce the above copyright
     13  * notice, this list of conditions and the following disclaimer in the
     14  * documentation and/or other materials provided with the distribution.
     15  *
     16  * - Neither the name of the Xiph.org Foundation nor the names of its
     17  * contributors may be used to endorse or promote products derived from
     18  * this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #ifdef HAVE_CONFIG_H
     34 #  include <config.h>
     35 #endif
     36 
     37 #include <stdlib.h>
     38 #include <string.h>
     39 
     40 #include "private/metadata.h"
     41 #include "private/memory.h"
     42 
     43 #include "FLAC/assert.h"
     44 #include "share/alloc.h"
     45 #include "share/compat.h"
     46 
     47 /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
     48 #define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
     49 
     50 
     51 /****************************************************************************
     52  *
     53  * Local routines
     54  *
     55  ***************************************************************************/
     56 
     57 /* copy bytes:
     58  *  from = NULL  && bytes = 0
     59  *       to <- NULL
     60  *  from != NULL && bytes > 0
     61  *       to <- copy of from
     62  *  else ASSERT
     63  * malloc error leaves 'to' unchanged
     64  */
     65 static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
     66 {
     67 	FLAC__ASSERT(to != NULL);
     68 	if (bytes > 0 && from != NULL) {
     69 		FLAC__byte *x;
     70 		if ((x = safe_malloc_(bytes)) == NULL)
     71 			return false;
     72 		memcpy(x, from, bytes);
     73 		*to = x;
     74 	}
     75 	else {
     76 		*to = 0;
     77 	}
     78 	return true;
     79 }
     80 
     81 #if 0 /* UNUSED */
     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)
     84 {
     85 	FLAC__byte *copy;
     86 	FLAC__ASSERT(to != NULL);
     87 	if (copy_bytes_(&copy, from, bytes)) {
     88 		free(*to);
     89 		*to = copy;
     90 		return true;
     91 	}
     92 	else
     93 		return false;
     94 }
     95 #endif
     96 
     97 /* reallocate entry to 1 byte larger and add a terminating NUL */
     98 /* realloc() failure leaves entry unchanged */
     99 static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
    100 {
    101 	FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1);
    102 	if (x != NULL) {
    103 		x[length] = '\0';
    104 		*entry = x;
    105 		return true;
    106 	}
    107 	else
    108 		return false;
    109 }
    110 
    111 /* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
    112  * unchanged if malloc fails, free()ing the original '*to' if it
    113  * succeeds and the original '*to' was not NULL
    114  */
    115 static FLAC__bool copy_cstring_(char **to, const char *from)
    116 {
    117 	char *copy = strdup(from);
    118 	FLAC__ASSERT(to != NULL);
    119 	if (copy) {
    120 		free(*to);
    121 		*to = copy;
    122 		return true;
    123 	}
    124 	else
    125 		return false;
    126 }
    127 
    128 static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
    129 {
    130 	to->length = from->length;
    131 	if (from->entry == 0) {
    132 		FLAC__ASSERT(from->length == 0);
    133 		to->entry = 0;
    134 	}
    135 	else {
    136 		FLAC__byte *x;
    137 		FLAC__ASSERT(from->length > 0);
    138 		if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL)
    139 			return false;
    140 		memcpy(x, from->entry, from->length);
    141 		x[from->length] = '\0';
    142 		to->entry = x;
    143 	}
    144 	return true;
    145 }
    146 
    147 static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
    148 {
    149 	memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
    150 	if (from->indices == 0) {
    151 		FLAC__ASSERT(from->num_indices == 0);
    152 	}
    153 	else {
    154 		FLAC__StreamMetadata_CueSheet_Index *x;
    155 		FLAC__ASSERT(from->num_indices > 0);
    156 		if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL)
    157 			return false;
    158 		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
    159 		to->indices = x;
    160 	}
    161 	return true;
    162 }
    163 
    164 static void seektable_calculate_length_(FLAC__StreamMetadata *object)
    165 {
    166 	FLAC__ASSERT(object != NULL);
    167 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
    168 
    169 	object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
    170 }
    171 
    172 static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
    173 {
    174 	FLAC__StreamMetadata_SeekPoint *object_array;
    175 
    176 	FLAC__ASSERT(num_points > 0);
    177 
    178 	object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
    179 
    180 	if (object_array != NULL) {
    181 		unsigned i;
    182 		for (i = 0; i < num_points; i++) {
    183 			object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
    184 			object_array[i].stream_offset = 0;
    185 			object_array[i].frame_samples = 0;
    186 		}
    187 	}
    188 
    189 	return object_array;
    190 }
    191 
    192 static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
    193 {
    194 	unsigned i;
    195 
    196 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
    197 
    198 	object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
    199 	object->length += object->data.vorbis_comment.vendor_string.length;
    200 	object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
    201 	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
    202 		object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
    203 		object->length += object->data.vorbis_comment.comments[i].length;
    204 	}
    205 }
    206 
    207 static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments)
    208 {
    209 	FLAC__ASSERT(num_comments > 0);
    210 
    211 	return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
    212 }
    213 
    214 static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
    215 {
    216 	unsigned i;
    217 
    218 	FLAC__ASSERT(object_array != NULL && num_comments > 0);
    219 
    220 	for (i = 0; i < num_comments; i++)
    221 		free(object_array[i].entry);
    222 
    223 	free(object_array);
    224 }
    225 
    226 static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
    227 {
    228 	FLAC__StreamMetadata_VorbisComment_Entry *return_array;
    229 
    230 	FLAC__ASSERT(object_array != NULL);
    231 	FLAC__ASSERT(num_comments > 0);
    232 
    233 	return_array = vorbiscomment_entry_array_new_(num_comments);
    234 
    235 	if (return_array != NULL) {
    236 		unsigned i;
    237 
    238 		for (i = 0; i < num_comments; i++) {
    239 			if (!copy_vcentry_(return_array+i, object_array+i)) {
    240 				vorbiscomment_entry_array_delete_(return_array, num_comments);
    241 				return 0;
    242 			}
    243 		}
    244 	}
    245 
    246 	return return_array;
    247 }
    248 
    249 static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
    250 {
    251 	FLAC__byte *save;
    252 
    253 	FLAC__ASSERT(object != NULL);
    254 	FLAC__ASSERT(dest != NULL);
    255 	FLAC__ASSERT(src != NULL);
    256 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
    257 	FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0));
    258 
    259 	save = dest->entry;
    260 
    261 	if (src->entry != NULL) {
    262 		if (copy) {
    263 			/* do the copy first so that if we fail we leave the dest object untouched */
    264 			if (!copy_vcentry_(dest, src))
    265 				return false;
    266 		}
    267 		else {
    268 			/* we have to make sure that the string we're taking over is null-terminated */
    269 
    270 			/*
    271 			 * Stripping the const from src->entry is OK since we're taking
    272 			 * ownership of the pointer.  This is a hack around a deficiency
    273 			 * in the API where the same function is used for 'copy' and
    274 			 * 'own', but the source entry is a const pointer.  If we were
    275 			 * precise, the 'own' flavor would be a separate function with a
    276 			 * non-const source pointer.  But it's not, so we hack away.
    277 			 */
    278 			if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
    279 				return false;
    280 			*dest = *src;
    281 		}
    282 	}
    283 	else {
    284 		/* the src is null */
    285 		*dest = *src;
    286 	}
    287 
    288 	free(save);
    289 
    290 	vorbiscomment_calculate_length_(object);
    291 	return true;
    292 }
    293 
    294 static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
    295 {
    296 	unsigned i;
    297 
    298 	FLAC__ASSERT(object != NULL);
    299 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
    300 	FLAC__ASSERT(field_name != NULL);
    301 
    302 	for (i = offset; i < object->data.vorbis_comment.num_comments; i++) {
    303 		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
    304 			return (int)i;
    305 	}
    306 
    307 	return -1;
    308 }
    309 
    310 static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
    311 {
    312 	unsigned i;
    313 
    314 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
    315 
    316 	object->length = (
    317 		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
    318 		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
    319 		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
    320 		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
    321 		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
    322 	) / 8;
    323 
    324 	object->length += object->data.cue_sheet.num_tracks * (
    325 		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
    326 		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
    327 		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
    328 		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
    329 		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
    330 		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
    331 		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
    332 	) / 8;
    333 
    334 	for (i = 0; i < object->data.cue_sheet.num_tracks; i++) {
    335 		object->length += object->data.cue_sheet.tracks[i].num_indices * (
    336 			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
    337 			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
    338 			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
    339 		) / 8;
    340 	}
    341 }
    342 
    343 static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
    344 {
    345 	FLAC__ASSERT(num_indices > 0);
    346 
    347 	return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
    348 }
    349 
    350 static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
    351 {
    352 	FLAC__ASSERT(num_tracks > 0);
    353 
    354 	return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
    355 }
    356 
    357 static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
    358 {
    359 	unsigned i;
    360 
    361 	FLAC__ASSERT(object_array != NULL && num_tracks > 0);
    362 
    363 	for (i = 0; i < num_tracks; i++) {
    364 		if (object_array[i].indices != 0) {
    365 			FLAC__ASSERT(object_array[i].num_indices > 0);
    366 			free(object_array[i].indices);
    367 		}
    368 	}
    369 
    370 	free(object_array);
    371 }
    372 
    373 static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
    374 {
    375 	FLAC__StreamMetadata_CueSheet_Track *return_array;
    376 
    377 	FLAC__ASSERT(object_array != NULL);
    378 	FLAC__ASSERT(num_tracks > 0);
    379 
    380 	return_array = cuesheet_track_array_new_(num_tracks);
    381 
    382 	if (return_array != NULL) {
    383 		unsigned i;
    384 
    385 		for (i = 0; i < num_tracks; i++) {
    386 			if (!copy_track_(return_array+i, object_array+i)) {
    387 				cuesheet_track_array_delete_(return_array, num_tracks);
    388 				return 0;
    389 			}
    390 		}
    391 	}
    392 
    393 	return return_array;
    394 }
    395 
    396 static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
    397 {
    398 	FLAC__StreamMetadata_CueSheet_Index *save;
    399 
    400 	FLAC__ASSERT(object != NULL);
    401 	FLAC__ASSERT(dest != NULL);
    402 	FLAC__ASSERT(src != NULL);
    403 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
    404 	FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0));
    405 
    406 	save = dest->indices;
    407 
    408 	/* do the copy first so that if we fail we leave the object untouched */
    409 	if (copy) {
    410 		if (!copy_track_(dest, src))
    411 			return false;
    412 	}
    413 	else {
    414 		*dest = *src;
    415 	}
    416 
    417 	free(save);
    418 
    419 	cuesheet_calculate_length_(object);
    420 	return true;
    421 }
    422 
    423 
    424 /****************************************************************************
    425  *
    426  * Metadata object routines
    427  *
    428  ***************************************************************************/
    429 
    430 FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
    431 {
    432 	FLAC__StreamMetadata *object;
    433 
    434 	if (type > FLAC__MAX_METADATA_TYPE)
    435 		return 0;
    436 
    437 	object = calloc(1, sizeof(FLAC__StreamMetadata));
    438 	if (object != NULL) {
    439 		object->is_last = false;
    440 		object->type = type;
    441 		switch(type) {
    442 			case FLAC__METADATA_TYPE_STREAMINFO:
    443 				object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
    444 				break;
    445 			case FLAC__METADATA_TYPE_PADDING:
    446 				/* calloc() took care of this for us:
    447 				object->length = 0;
    448 				*/
    449 				break;
    450 			case FLAC__METADATA_TYPE_APPLICATION:
    451 				object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
    452 				/* calloc() took care of this for us:
    453 				object->data.application.data = 0;
    454 				*/
    455 				break;
    456 			case FLAC__METADATA_TYPE_SEEKTABLE:
    457 				/* calloc() took care of this for us:
    458 				object->length = 0;
    459 				object->data.seek_table.num_points = 0;
    460 				object->data.seek_table.points = 0;
    461 				*/
    462 				break;
    463 			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
    464 				object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
    465 				if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
    466 					free(object);
    467 					return 0;
    468 				}
    469 				vorbiscomment_calculate_length_(object);
    470 				break;
    471 			case FLAC__METADATA_TYPE_CUESHEET:
    472 				cuesheet_calculate_length_(object);
    473 				break;
    474 			case FLAC__METADATA_TYPE_PICTURE:
    475 				object->length = (
    476 					FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
    477 					FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
    478 					FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
    479 					FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
    480 					FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
    481 					FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
    482 					FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
    483 					FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
    484 					0 /* no data */
    485 				) / 8;
    486 				object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
    487 				object->data.picture.mime_type = 0;
    488 				object->data.picture.description = 0;
    489 				/* calloc() took care of this for us:
    490 				object->data.picture.width = 0;
    491 				object->data.picture.height = 0;
    492 				object->data.picture.depth = 0;
    493 				object->data.picture.colors = 0;
    494 				object->data.picture.data_length = 0;
    495 				object->data.picture.data = 0;
    496 				*/
    497 				/* now initialize mime_type and description with empty strings to make things easier on the client */
    498 				if (!copy_cstring_(&object->data.picture.mime_type, "")) {
    499 					free(object);
    500 					return 0;
    501 				}
    502 				if (!copy_cstring_((char**)(&object->data.picture.description), "")) {
    503 					free(object->data.picture.mime_type);
    504 					free(object);
    505 					return 0;
    506 				}
    507 				break;
    508 			default:
    509 				/* calloc() took care of this for us:
    510 				object->length = 0;
    511 				object->data.unknown.data = 0;
    512 				*/
    513 				break;
    514 		}
    515 	}
    516 
    517 	return object;
    518 }
    519 
    520 FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
    521 {
    522 	FLAC__StreamMetadata *to;
    523 
    524 	FLAC__ASSERT(object != NULL);
    525 
    526 	if ((to = FLAC__metadata_object_new(object->type)) != NULL) {
    527 		to->is_last = object->is_last;
    528 		to->type = object->type;
    529 		to->length = object->length;
    530 		switch(to->type) {
    531 			case FLAC__METADATA_TYPE_STREAMINFO:
    532 				memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
    533 				break;
    534 			case FLAC__METADATA_TYPE_PADDING:
    535 				break;
    536 			case FLAC__METADATA_TYPE_APPLICATION:
    537 				if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */
    538 					FLAC__metadata_object_delete(to);
    539 					return 0;
    540 				}
    541 				memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
    542 				if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
    543 					FLAC__metadata_object_delete(to);
    544 					return 0;
    545 				}
    546 				break;
    547 			case FLAC__METADATA_TYPE_SEEKTABLE:
    548 				to->data.seek_table.num_points = object->data.seek_table.num_points;
    549 				if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */
    550 					FLAC__metadata_object_delete(to);
    551 					return 0;
    552 				}
    553 				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))) {
    554 					FLAC__metadata_object_delete(to);
    555 					return 0;
    556 				}
    557 				break;
    558 			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
    559 				if (to->data.vorbis_comment.vendor_string.entry != NULL) {
    560 					free(to->data.vorbis_comment.vendor_string.entry);
    561 					to->data.vorbis_comment.vendor_string.entry = 0;
    562 				}
    563 				if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
    564 					FLAC__metadata_object_delete(to);
    565 					return 0;
    566 				}
    567 				if (object->data.vorbis_comment.num_comments == 0) {
    568 					to->data.vorbis_comment.comments = 0;
    569 				}
    570 				else {
    571 					to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
    572 					if (to->data.vorbis_comment.comments == NULL) {
    573 						to->data.vorbis_comment.num_comments = 0;
    574 						FLAC__metadata_object_delete(to);
    575 						return 0;
    576 					}
    577 				}
    578 				to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
    579 				break;
    580 			case FLAC__METADATA_TYPE_CUESHEET:
    581 				memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
    582 				if (object->data.cue_sheet.num_tracks == 0) {
    583 					FLAC__ASSERT(object->data.cue_sheet.tracks == NULL);
    584 				}
    585 				else {
    586 					FLAC__ASSERT(object->data.cue_sheet.tracks != 0);
    587 					to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
    588 					if (to->data.cue_sheet.tracks == NULL) {
    589 						FLAC__metadata_object_delete(to);
    590 						return 0;
    591 					}
    592 				}
    593 				break;
    594 			case FLAC__METADATA_TYPE_PICTURE:
    595 				to->data.picture.type = object->data.picture.type;
    596 				if (!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
    597 					FLAC__metadata_object_delete(to);
    598 					return 0;
    599 				}
    600 				if (!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
    601 					FLAC__metadata_object_delete(to);
    602 					return 0;
    603 				}
    604 				to->data.picture.width = object->data.picture.width;
    605 				to->data.picture.height = object->data.picture.height;
    606 				to->data.picture.depth = object->data.picture.depth;
    607 				to->data.picture.colors = object->data.picture.colors;
    608 				to->data.picture.data_length = object->data.picture.data_length;
    609 				if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
    610 					FLAC__metadata_object_delete(to);
    611 					return 0;
    612 				}
    613 				break;
    614 			default:
    615 				if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
    616 					FLAC__metadata_object_delete(to);
    617 					return 0;
    618 				}
    619 				break;
    620 		}
    621 	}
    622 
    623 	return to;
    624 }
    625 
    626 void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
    627 {
    628 	FLAC__ASSERT(object != NULL);
    629 
    630 	switch(object->type) {
    631 		case FLAC__METADATA_TYPE_STREAMINFO:
    632 		case FLAC__METADATA_TYPE_PADDING:
    633 			break;
    634 		case FLAC__METADATA_TYPE_APPLICATION:
    635 			if (object->data.application.data != NULL) {
    636 				free(object->data.application.data);
    637 				object->data.application.data = NULL;
    638 			}
    639 			break;
    640 		case FLAC__METADATA_TYPE_SEEKTABLE:
    641 			if (object->data.seek_table.points != NULL) {
    642 				free(object->data.seek_table.points);
    643 				object->data.seek_table.points = NULL;
    644 			}
    645 			break;
    646 		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
    647 			if (object->data.vorbis_comment.vendor_string.entry != NULL) {
    648 				free(object->data.vorbis_comment.vendor_string.entry);
    649 				object->data.vorbis_comment.vendor_string.entry = 0;
    650 			}
    651 			if (object->data.vorbis_comment.comments != NULL) {
    652 				FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
    653 				vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
    654 				object->data.vorbis_comment.comments = NULL;
    655 				object->data.vorbis_comment.num_comments = 0;
    656 			}
    657 			break;
    658 		case FLAC__METADATA_TYPE_CUESHEET:
    659 			if (object->data.cue_sheet.tracks != NULL) {
    660 				FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
    661 				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
    662 				object->data.cue_sheet.tracks = NULL;
    663 				object->data.cue_sheet.num_tracks = 0;
    664 			}
    665 			break;
    666 		case FLAC__METADATA_TYPE_PICTURE:
    667 			if (object->data.picture.mime_type != NULL) {
    668 				free(object->data.picture.mime_type);
    669 				object->data.picture.mime_type = NULL;
    670 			}
    671 			if (object->data.picture.description != NULL) {
    672 				free(object->data.picture.description);
    673 				object->data.picture.description = NULL;
    674 			}
    675 			if (object->data.picture.data != NULL) {
    676 				free(object->data.picture.data);
    677 				object->data.picture.data = NULL;
    678 			}
    679 			break;
    680 		default:
    681 			if (object->data.unknown.data != NULL) {
    682 				free(object->data.unknown.data);
    683 				object->data.unknown.data = NULL;
    684 			}
    685 			break;
    686 	}
    687 }
    688 
    689 FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
    690 {
    691 	FLAC__metadata_object_delete_data(object);
    692 	free(object);
    693 }
    694 
    695 static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
    696 {
    697 	if (block1->min_blocksize != block2->min_blocksize)
    698 		return false;
    699 	if (block1->max_blocksize != block2->max_blocksize)
    700 		return false;
    701 	if (block1->min_framesize != block2->min_framesize)
    702 		return false;
    703 	if (block1->max_framesize != block2->max_framesize)
    704 		return false;
    705 	if (block1->sample_rate != block2->sample_rate)
    706 		return false;
    707 	if (block1->channels != block2->channels)
    708 		return false;
    709 	if (block1->bits_per_sample != block2->bits_per_sample)
    710 		return false;
    711 	if (block1->total_samples != block2->total_samples)
    712 		return false;
    713 	if (memcmp(block1->md5sum, block2->md5sum, 16) != 0)
    714 		return false;
    715 	return true;
    716 }
    717 
    718 static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, unsigned block_length)
    719 {
    720 	FLAC__ASSERT(block1 != NULL);
    721 	FLAC__ASSERT(block2 != NULL);
    722 	FLAC__ASSERT(block_length >= sizeof(block1->id));
    723 
    724 	if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0)
    725 		return false;
    726 	if (block1->data != NULL && block2->data != NULL)
    727 		return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0;
    728 	else
    729 		return block1->data == block2->data;
    730 }
    731 
    732 static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
    733 {
    734 	unsigned i;
    735 
    736 	FLAC__ASSERT(block1 != NULL);
    737 	FLAC__ASSERT(block2 != NULL);
    738 
    739 	if (block1->num_points != block2->num_points)
    740 		return false;
    741 
    742 	if (block1->points != NULL && block2->points != NULL) {
    743 		for (i = 0; i < block1->num_points; i++) {
    744 			if (block1->points[i].sample_number != block2->points[i].sample_number)
    745 				return false;
    746 			if (block1->points[i].stream_offset != block2->points[i].stream_offset)
    747 				return false;
    748 			if (block1->points[i].frame_samples != block2->points[i].frame_samples)
    749 				return false;
    750 		}
    751 		return true;
    752 	}
    753 	else
    754 		return block1->points == block2->points;
    755 }
    756 
    757 static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
    758 {
    759 	unsigned i;
    760 
    761 	if (block1->vendor_string.length != block2->vendor_string.length)
    762 		return false;
    763 
    764 	if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) {
    765 		if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0)
    766 			return false;
    767 	}
    768 	else if (block1->vendor_string.entry != block2->vendor_string.entry)
    769 		return false;
    770 
    771 	if (block1->num_comments != block2->num_comments)
    772 		return false;
    773 
    774 	for (i = 0; i < block1->num_comments; i++) {
    775 		if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) {
    776 			if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0)
    777 				return false;
    778 		}
    779 		else if (block1->comments[i].entry != block2->comments[i].entry)
    780 			return false;
    781 	}
    782 	return true;
    783 }
    784 
    785 static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
    786 {
    787 	unsigned i, j;
    788 
    789 	if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0)
    790 		return false;
    791 
    792 	if (block1->lead_in != block2->lead_in)
    793 		return false;
    794 
    795 	if (block1->is_cd != block2->is_cd)
    796 		return false;
    797 
    798 	if (block1->num_tracks != block2->num_tracks)
    799 		return false;
    800 
    801 	if (block1->tracks != NULL && block2->tracks != NULL) {
    802 		FLAC__ASSERT(block1->num_tracks > 0);
    803 		for (i = 0; i < block1->num_tracks; i++) {
    804 			if (block1->tracks[i].offset != block2->tracks[i].offset)
    805 				return false;
    806 			if (block1->tracks[i].number != block2->tracks[i].number)
    807 				return false;
    808 			if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0)
    809 				return false;
    810 			if (block1->tracks[i].type != block2->tracks[i].type)
    811 				return false;
    812 			if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
    813 				return false;
    814 			if (block1->tracks[i].num_indices != block2->tracks[i].num_indices)
    815 				return false;
    816 			if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) {
    817 				FLAC__ASSERT(block1->tracks[i].num_indices > 0);
    818 				for (j = 0; j < block1->tracks[i].num_indices; j++) {
    819 					if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
    820 						return false;
    821 					if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
    822 						return false;
    823 				}
    824 			}
    825 			else if (block1->tracks[i].indices != block2->tracks[i].indices)
    826 				return false;
    827 		}
    828 	}
    829 	else if (block1->tracks != block2->tracks)
    830 		return false;
    831 	return true;
    832 }
    833 
    834 static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
    835 {
    836 	if (block1->type != block2->type)
    837 		return false;
    838 	if (block1->mime_type != block2->mime_type && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type)))
    839 		return false;
    840 	if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || strcmp((const char *)block1->description, (const char *)block2->description)))
    841 		return false;
    842 	if (block1->width != block2->width)
    843 		return false;
    844 	if (block1->height != block2->height)
    845 		return false;
    846 	if (block1->depth != block2->depth)
    847 		return false;
    848 	if (block1->colors != block2->colors)
    849 		return false;
    850 	if (block1->data_length != block2->data_length)
    851 		return false;
    852 	if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length)))
    853 		return false;
    854 	return true;
    855 }
    856 
    857 static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length)
    858 {
    859 	FLAC__ASSERT(block1 != NULL);
    860 	FLAC__ASSERT(block2 != NULL);
    861 
    862 	if (block1->data != NULL && block2->data != NULL)
    863 		return memcmp(block1->data, block2->data, block_length) == 0;
    864 	else
    865 		return block1->data == block2->data;
    866 }
    867 
    868 FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
    869 {
    870 	FLAC__ASSERT(block1 != NULL);
    871 	FLAC__ASSERT(block2 != NULL);
    872 
    873 	if (block1->type != block2->type) {
    874 		return false;
    875 	}
    876 	if (block1->is_last != block2->is_last) {
    877 		return false;
    878 	}
    879 	if (block1->length != block2->length) {
    880 		return false;
    881 	}
    882 	switch(block1->type) {
    883 		case FLAC__METADATA_TYPE_STREAMINFO:
    884 			return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
    885 		case FLAC__METADATA_TYPE_PADDING:
    886 			return true; /* we don't compare the padding guts */
    887 		case FLAC__METADATA_TYPE_APPLICATION:
    888 			return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
    889 		case FLAC__METADATA_TYPE_SEEKTABLE:
    890 			return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
    891 		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
    892 			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
    893 		case FLAC__METADATA_TYPE_CUESHEET:
    894 			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
    895 		case FLAC__METADATA_TYPE_PICTURE:
    896 			return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
    897 		default:
    898 			return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
    899 	}
    900 }
    901 
    902 FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy)
    903 {
    904 	FLAC__byte *save;
    905 
    906 	FLAC__ASSERT(object != NULL);
    907 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
    908 	FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false));
    909 
    910 	save = object->data.application.data;
    911 
    912 	/* do the copy first so that if we fail we leave the object untouched */
    913 	if (copy) {
    914 		if (!copy_bytes_(&object->data.application.data, data, length))
    915 			return false;
    916 	}
    917 	else {
    918 		object->data.application.data = data;
    919 	}
    920 
    921 	free(save);
    922 
    923 	object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
    924 	return true;
    925 }
    926 
    927 FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points)
    928 {
    929 	FLAC__ASSERT(object != NULL);
    930 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
    931 
    932 	if (object->data.seek_table.points == 0) {
    933 		FLAC__ASSERT(object->data.seek_table.num_points == 0);
    934 		if (new_num_points == 0)
    935 			return true;
    936 		else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0)
    937 			return false;
    938 	}
    939 	else {
    940 		const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
    941 		const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
    942 
    943 		/* overflow check */
    944 		if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint))
    945 			return false;
    946 
    947 		FLAC__ASSERT(object->data.seek_table.num_points > 0);
    948 
    949 		if (new_size == 0) {
    950 			free(object->data.seek_table.points);
    951 			object->data.seek_table.points = 0;
    952 		}
    953 		else if ((object->data.seek_table.points = safe_realloc_(object->data.seek_table.points, new_size)) == NULL)
    954 			return false;
    955 
    956 		/* if growing, set new elements to placeholders */
    957 		if (new_size > old_size) {
    958 			unsigned i;
    959 			for (i = object->data.seek_table.num_points; i < new_num_points; i++) {
    960 				object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
    961 				object->data.seek_table.points[i].stream_offset = 0;
    962 				object->data.seek_table.points[i].frame_samples = 0;
    963 			}
    964 		}
    965 	}
    966 
    967 	object->data.seek_table.num_points = new_num_points;
    968 
    969 	seektable_calculate_length_(object);
    970 	return true;
    971 }
    972 
    973 FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
    974 {
    975 	FLAC__ASSERT(object != NULL);
    976 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
    977 	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
    978 
    979 	object->data.seek_table.points[point_num] = point;
    980 }
    981 
    982 FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
    983 {
    984 	int i;
    985 
    986 	FLAC__ASSERT(object != NULL);
    987 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
    988 	FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
    989 
    990 	if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
    991 		return false;
    992 
    993 	/* move all points >= point_num forward one space */
    994 	for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
    995 		object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
    996 
    997 	FLAC__metadata_object_seektable_set_point(object, point_num, point);
    998 	seektable_calculate_length_(object);
    999 	return true;
   1000 }
   1001 
   1002 FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num)
   1003 {
   1004 	unsigned i;
   1005 
   1006 	FLAC__ASSERT(object != NULL);
   1007 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1008 	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
   1009 
   1010 	/* move all points > point_num backward one space */
   1011 	for (i = point_num; i < object->data.seek_table.num_points-1; i++)
   1012 		object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
   1013 
   1014 	return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
   1015 }
   1016 
   1017 FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
   1018 {
   1019 	FLAC__ASSERT(object != NULL);
   1020 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1021 
   1022 	return FLAC__format_seektable_is_legal(&object->data.seek_table);
   1023 }
   1024 
   1025 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num)
   1026 {
   1027 	FLAC__ASSERT(object != NULL);
   1028 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1029 
   1030 	if (num > 0)
   1031 		/* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
   1032 		return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
   1033 	else
   1034 		return true;
   1035 }
   1036 
   1037 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
   1038 {
   1039 	FLAC__StreamMetadata_SeekTable *seek_table;
   1040 
   1041 	FLAC__ASSERT(object != NULL);
   1042 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1043 
   1044 	seek_table = &object->data.seek_table;
   1045 
   1046 	if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
   1047 		return false;
   1048 
   1049 	seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
   1050 	seek_table->points[seek_table->num_points - 1].stream_offset = 0;
   1051 	seek_table->points[seek_table->num_points - 1].frame_samples = 0;
   1052 
   1053 	return true;
   1054 }
   1055 
   1056 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num)
   1057 {
   1058 	FLAC__ASSERT(object != NULL);
   1059 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1060 	FLAC__ASSERT(sample_numbers != 0 || num == 0);
   1061 
   1062 	if (num > 0) {
   1063 		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
   1064 		unsigned i, j;
   1065 
   1066 		i = seek_table->num_points;
   1067 
   1068 		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
   1069 			return false;
   1070 
   1071 		for (j = 0; j < num; i++, j++) {
   1072 			seek_table->points[i].sample_number = sample_numbers[j];
   1073 			seek_table->points[i].stream_offset = 0;
   1074 			seek_table->points[i].frame_samples = 0;
   1075 		}
   1076 	}
   1077 
   1078 	return true;
   1079 }
   1080 
   1081 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples)
   1082 {
   1083 	FLAC__ASSERT(object != NULL);
   1084 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1085 	FLAC__ASSERT(total_samples > 0);
   1086 
   1087 	if (num > 0 && total_samples > 0) {
   1088 		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
   1089 		unsigned i, j;
   1090 
   1091 		i = seek_table->num_points;
   1092 
   1093 		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
   1094 			return false;
   1095 
   1096 		for (j = 0; j < num; i++, j++) {
   1097 			seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
   1098 			seek_table->points[i].stream_offset = 0;
   1099 			seek_table->points[i].frame_samples = 0;
   1100 		}
   1101 	}
   1102 
   1103 	return true;
   1104 }
   1105 
   1106 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples)
   1107 {
   1108 	FLAC__ASSERT(object != NULL);
   1109 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1110 	FLAC__ASSERT(samples > 0);
   1111 	FLAC__ASSERT(total_samples > 0);
   1112 
   1113 	if (samples > 0 && total_samples > 0) {
   1114 		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
   1115 		unsigned i, j;
   1116 		FLAC__uint64 num, sample;
   1117 
   1118 		num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
   1119 		/* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
   1120 		if (total_samples % samples == 0)
   1121 			num--;
   1122 
   1123 		/* Put a strict upper bound on the number of allowed seek points. */
   1124 		if (num > 32768) {
   1125 			/* Set the bound and recalculate samples accordingly. */
   1126 			num = 32768;
   1127 			samples = total_samples / num;
   1128 		}
   1129 
   1130 		i = seek_table->num_points;
   1131 
   1132 		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (unsigned)num))
   1133 			return false;
   1134 
   1135 		sample = 0;
   1136 		for (j = 0; j < num; i++, j++, sample += samples) {
   1137 			seek_table->points[i].sample_number = sample;
   1138 			seek_table->points[i].stream_offset = 0;
   1139 			seek_table->points[i].frame_samples = 0;
   1140 		}
   1141 	}
   1142 
   1143 	return true;
   1144 }
   1145 
   1146 FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
   1147 {
   1148 	unsigned unique;
   1149 
   1150 	FLAC__ASSERT(object != NULL);
   1151 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
   1152 
   1153 	unique = FLAC__format_seektable_sort(&object->data.seek_table);
   1154 
   1155 	return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
   1156 }
   1157 
   1158 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
   1159 {
   1160 	if (!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
   1161 		return false;
   1162 	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
   1163 }
   1164 
   1165 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments)
   1166 {
   1167 	FLAC__ASSERT(object != NULL);
   1168 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
   1169 
   1170 	if (object->data.vorbis_comment.comments == NULL) {
   1171 		FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
   1172 		if (new_num_comments == 0)
   1173 			return true;
   1174 		else if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL)
   1175 			return false;
   1176 	}
   1177 	else {
   1178 		const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
   1179 		const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
   1180 
   1181 		/* overflow check */
   1182 		if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry))
   1183 			return false;
   1184 
   1185 		FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
   1186 
   1187 		/* if shrinking, free the truncated entries */
   1188 		if (new_num_comments < object->data.vorbis_comment.num_comments) {
   1189 			unsigned i;
   1190 			for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
   1191 				if (object->data.vorbis_comment.comments[i].entry != NULL)
   1192 					free(object->data.vorbis_comment.comments[i].entry);
   1193 		}
   1194 
   1195 		if (new_size == 0) {
   1196 			free(object->data.vorbis_comment.comments);
   1197 			object->data.vorbis_comment.comments = 0;
   1198 		}
   1199 		else {
   1200 			FLAC__StreamMetadata_VorbisComment_Entry *oldptr = object->data.vorbis_comment.comments;
   1201 			if ((object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) {
   1202 				vorbiscomment_entry_array_delete_(oldptr, object->data.vorbis_comment.num_comments);
   1203 				object->data.vorbis_comment.num_comments = 0;
   1204 				return false;
   1205 			}
   1206 		}
   1207 
   1208 		/* if growing, zero all the length/pointers of new elements */
   1209 		if (new_size > old_size)
   1210 			memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
   1211 	}
   1212 
   1213 	object->data.vorbis_comment.num_comments = new_num_comments;
   1214 
   1215 	vorbiscomment_calculate_length_(object);
   1216 	return true;
   1217 }
   1218 
   1219 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
   1220 {
   1221 	FLAC__ASSERT(object != NULL);
   1222 	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
   1223 
   1224 	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
   1225 		return false;
   1226 	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
   1227 }
   1228 
   1229 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
   1230 {
   1231 	FLAC__StreamMetadata_VorbisComment *vc;
   1232 
   1233 	FLAC__ASSERT(object != NULL);
   1234 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
   1235 	FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
   1236 
   1237 	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
   1238 		return false;
   1239 
   1240 	vc = &object->data.vorbis_comment;
   1241 
   1242 	if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
   1243 		return false;
   1244 
   1245 	/* move all comments >= comment_num forward one space */
   1246 	memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
   1247 	vc->comments[comment_num].length = 0;
   1248 	vc->comments[comment_num].entry = 0;
   1249 
   1250 	return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
   1251 }
   1252 
   1253 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
   1254 {
   1255 	FLAC__ASSERT(object != NULL);
   1256 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
   1257 	return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
   1258 }
   1259 
   1260 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
   1261 {
   1262 	FLAC__ASSERT(entry.entry != NULL && entry.length > 0);
   1263 
   1264 	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
   1265 		return false;
   1266 
   1267 	{
   1268 		int i;
   1269 		size_t field_name_length;
   1270 		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
   1271 
   1272 		if (eq == NULL)
   1273 			return false; /* double protection */
   1274 
   1275 		field_name_length = eq-entry.entry;
   1276 
   1277 		i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length);
   1278 		if (i >= 0) {
   1279 			unsigned indx = (unsigned)i;
   1280 			if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy))
   1281 				return false;
   1282 			entry = object->data.vorbis_comment.comments[indx];
   1283 			indx++; /* skip over replaced comment */
   1284 			if (all && indx < object->data.vorbis_comment.num_comments) {
   1285 				i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length);
   1286 				while (i >= 0) {
   1287 					indx = (unsigned)i;
   1288 					if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx))
   1289 						return false;
   1290 					if (indx < object->data.vorbis_comment.num_comments)
   1291 						i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length);
   1292 					else
   1293 						i = -1;
   1294 				}
   1295 			}
   1296 			return true;
   1297 		}
   1298 		else
   1299 			return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
   1300 	}
   1301 }
   1302 
   1303 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
   1304 {
   1305 	FLAC__StreamMetadata_VorbisComment *vc;
   1306 
   1307 	FLAC__ASSERT(object != NULL);
   1308 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
   1309 	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
   1310 
   1311 	vc = &object->data.vorbis_comment;
   1312 
   1313 	/* free the comment at comment_num */
   1314 	free(vc->comments[comment_num].entry);
   1315 
   1316 	/* move all comments > comment_num backward one space */
   1317 	memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
   1318 	vc->comments[vc->num_comments-1].length = 0;
   1319 	vc->comments[vc->num_comments-1].entry = 0;
   1320 
   1321 	return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
   1322 }
   1323 
   1324 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)
   1325 {
   1326 	FLAC__ASSERT(entry != NULL);
   1327 	FLAC__ASSERT(field_name != NULL);
   1328 	FLAC__ASSERT(field_value != NULL);
   1329 
   1330 	if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
   1331 		return false;
   1332 	if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (unsigned)(-1)))
   1333 		return false;
   1334 
   1335 	{
   1336 		const size_t nn = strlen(field_name);
   1337 		const size_t nv = strlen(field_value);
   1338 		entry->length = nn + 1 /*=*/ + nv;
   1339 		if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL)
   1340 			return false;
   1341 		memcpy(entry->entry, field_name, nn);
   1342 		entry->entry[nn] = '=';
   1343 		memcpy(entry->entry+nn+1, field_value, nv);
   1344 		entry->entry[entry->length] = '\0';
   1345 	}
   1346 
   1347 	return true;
   1348 }
   1349 
   1350 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)
   1351 {
   1352 	FLAC__ASSERT(entry.entry != NULL && entry.length > 0);
   1353 	FLAC__ASSERT(field_name != NULL);
   1354 	FLAC__ASSERT(field_value != NULL);
   1355 
   1356 	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
   1357 		return false;
   1358 
   1359 	{
   1360 		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
   1361 		const size_t nn = eq-entry.entry;
   1362 		const size_t nv = entry.length-nn-1; /* -1 for the '=' */
   1363 
   1364 		if (eq == NULL)
   1365 			return false; /* double protection */
   1366 		if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL)
   1367 			return false;
   1368 		if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) {
   1369 			free(*field_name);
   1370 			return false;
   1371 		}
   1372 		memcpy(*field_name, entry.entry, nn);
   1373 		memcpy(*field_value, entry.entry+nn+1, nv);
   1374 		(*field_name)[nn] = '\0';
   1375 		(*field_value)[nv] = '\0';
   1376 	}
   1377 
   1378 	return true;
   1379 }
   1380 
   1381 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length)
   1382 {
   1383 	FLAC__ASSERT(entry.entry != NULL && entry.length > 0);
   1384 	{
   1385 		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
   1386 		return (eq != NULL && (unsigned)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0);
   1387 	}
   1388 }
   1389 
   1390 FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
   1391 {
   1392 	FLAC__ASSERT(field_name != NULL);
   1393 
   1394 	return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name));
   1395 }
   1396 
   1397 FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
   1398 {
   1399 	const unsigned field_name_length = strlen(field_name);
   1400 	unsigned i;
   1401 
   1402 	FLAC__ASSERT(object != NULL);
   1403 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
   1404 
   1405 	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
   1406 		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
   1407 			if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
   1408 				return -1;
   1409 			else
   1410 				return 1;
   1411 		}
   1412 	}
   1413 
   1414 	return 0;
   1415 }
   1416 
   1417 FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
   1418 {
   1419 	FLAC__bool ok = true;
   1420 	unsigned matching = 0;
   1421 	const unsigned field_name_length = strlen(field_name);
   1422 	int i;
   1423 
   1424 	FLAC__ASSERT(object != NULL);
   1425 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
   1426 
   1427 	/* must delete from end to start otherwise it will interfere with our iteration */
   1428 	for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
   1429 		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
   1430 			matching++;
   1431 			ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
   1432 		}
   1433 	}
   1434 
   1435 	return ok? (int)matching : -1;
   1436 }
   1437 
   1438 FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
   1439 {
   1440 	return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
   1441 }
   1442 
   1443 FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
   1444 {
   1445 	FLAC__StreamMetadata_CueSheet_Track *to;
   1446 
   1447 	FLAC__ASSERT(object != NULL);
   1448 
   1449 	if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) {
   1450 		if (!copy_track_(to, object)) {
   1451 			FLAC__metadata_object_cuesheet_track_delete(to);
   1452 			return 0;
   1453 		}
   1454 	}
   1455 
   1456 	return to;
   1457 }
   1458 
   1459 void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
   1460 {
   1461 	FLAC__ASSERT(object != NULL);
   1462 
   1463 	if (object->indices != NULL) {
   1464 		FLAC__ASSERT(object->num_indices > 0);
   1465 		free(object->indices);
   1466 	}
   1467 }
   1468 
   1469 FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
   1470 {
   1471 	FLAC__metadata_object_cuesheet_track_delete_data(object);
   1472 	free(object);
   1473 }
   1474 
   1475 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
   1476 {
   1477 	FLAC__StreamMetadata_CueSheet_Track *track;
   1478 	FLAC__ASSERT(object != NULL);
   1479 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1480 	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
   1481 
   1482 	track = &object->data.cue_sheet.tracks[track_num];
   1483 
   1484 	if (track->indices == NULL) {
   1485 		FLAC__ASSERT(track->num_indices == 0);
   1486 		if (new_num_indices == 0)
   1487 			return true;
   1488 		else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL)
   1489 			return false;
   1490 	}
   1491 	else {
   1492 		const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
   1493 		const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
   1494 
   1495 		/* overflow check */
   1496 		if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index))
   1497 			return false;
   1498 
   1499 		FLAC__ASSERT(track->num_indices > 0);
   1500 
   1501 		if (new_size == 0) {
   1502 			free(track->indices);
   1503 			track->indices = 0;
   1504 		}
   1505 		else if ((track->indices = safe_realloc_(track->indices, new_size)) == NULL)
   1506 			return false;
   1507 
   1508 		/* if growing, zero all the lengths/pointers of new elements */
   1509 		if (new_size > old_size)
   1510 			memset(track->indices + track->num_indices, 0, new_size - old_size);
   1511 	}
   1512 
   1513 	track->num_indices = new_num_indices;
   1514 
   1515 	cuesheet_calculate_length_(object);
   1516 	return true;
   1517 }
   1518 
   1519 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index indx)
   1520 {
   1521 	FLAC__StreamMetadata_CueSheet_Track *track;
   1522 
   1523 	FLAC__ASSERT(object != NULL);
   1524 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1525 	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
   1526 	FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
   1527 
   1528 	track = &object->data.cue_sheet.tracks[track_num];
   1529 
   1530 	if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
   1531 		return false;
   1532 
   1533 	/* move all indices >= index_num forward one space */
   1534 	memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
   1535 
   1536 	track->indices[index_num] = indx;
   1537 	cuesheet_calculate_length_(object);
   1538 	return true;
   1539 }
   1540 
   1541 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
   1542 {
   1543 	FLAC__StreamMetadata_CueSheet_Index indx;
   1544 	memset(&indx, 0, sizeof(indx));
   1545 	return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx);
   1546 }
   1547 
   1548 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
   1549 {
   1550 	FLAC__StreamMetadata_CueSheet_Track *track;
   1551 
   1552 	FLAC__ASSERT(object != NULL);
   1553 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1554 	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
   1555 	FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
   1556 
   1557 	track = &object->data.cue_sheet.tracks[track_num];
   1558 
   1559 	/* move all indices > index_num backward one space */
   1560 	memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
   1561 
   1562 	FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
   1563 	cuesheet_calculate_length_(object);
   1564 	return true;
   1565 }
   1566 
   1567 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
   1568 {
   1569 	FLAC__ASSERT(object != NULL);
   1570 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1571 
   1572 	if (object->data.cue_sheet.tracks == NULL) {
   1573 		FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
   1574 		if (new_num_tracks == 0)
   1575 			return true;
   1576 		else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL)
   1577 			return false;
   1578 	}
   1579 	else {
   1580 		const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
   1581 		const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
   1582 
   1583 		/* overflow check */
   1584 		if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track))
   1585 			return false;
   1586 
   1587 		FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
   1588 
   1589 		/* if shrinking, free the truncated entries */
   1590 		if (new_num_tracks < object->data.cue_sheet.num_tracks) {
   1591 			unsigned i;
   1592 			for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
   1593 				free(object->data.cue_sheet.tracks[i].indices);
   1594 		}
   1595 
   1596 		if (new_size == 0) {
   1597 			free(object->data.cue_sheet.tracks);
   1598 			object->data.cue_sheet.tracks = 0;
   1599 		}
   1600 		else if ((object->data.cue_sheet.tracks = safe_realloc_(object->data.cue_sheet.tracks, new_size)) == NULL)
   1601 			return false;
   1602 
   1603 		/* if growing, zero all the lengths/pointers of new elements */
   1604 		if (new_size > old_size)
   1605 			memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
   1606 	}
   1607 
   1608 	object->data.cue_sheet.num_tracks = new_num_tracks;
   1609 
   1610 	cuesheet_calculate_length_(object);
   1611 	return true;
   1612 }
   1613 
   1614 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
   1615 {
   1616 	FLAC__ASSERT(object != NULL);
   1617 	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
   1618 
   1619 	return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
   1620 }
   1621 
   1622 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
   1623 {
   1624 	FLAC__StreamMetadata_CueSheet *cs;
   1625 
   1626 	FLAC__ASSERT(object != NULL);
   1627 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1628 	FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
   1629 
   1630 	cs = &object->data.cue_sheet;
   1631 
   1632 	if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
   1633 		return false;
   1634 
   1635 	/* move all tracks >= track_num forward one space */
   1636 	memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
   1637 	cs->tracks[track_num].num_indices = 0;
   1638 	cs->tracks[track_num].indices = 0;
   1639 
   1640 	return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
   1641 }
   1642 
   1643 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num)
   1644 {
   1645 	FLAC__StreamMetadata_CueSheet_Track track;
   1646 	memset(&track, 0, sizeof(track));
   1647 	return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
   1648 }
   1649 
   1650 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
   1651 {
   1652 	FLAC__StreamMetadata_CueSheet *cs;
   1653 
   1654 	FLAC__ASSERT(object != NULL);
   1655 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1656 	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
   1657 
   1658 	cs = &object->data.cue_sheet;
   1659 
   1660 	/* free the track at track_num */
   1661 	free(cs->tracks[track_num].indices);
   1662 
   1663 	/* move all tracks > track_num backward one space */
   1664 	memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
   1665 	cs->tracks[cs->num_tracks-1].num_indices = 0;
   1666 	cs->tracks[cs->num_tracks-1].indices = 0;
   1667 
   1668 	return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
   1669 }
   1670 
   1671 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
   1672 {
   1673 	FLAC__ASSERT(object != NULL);
   1674 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1675 
   1676 	return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
   1677 }
   1678 
   1679 static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track)
   1680 {
   1681 	if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
   1682 		return 0;
   1683 	else if (cs->tracks[track].indices[0].number == 1)
   1684 		return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
   1685 	else if (cs->tracks[track].num_indices < 2)
   1686 		return 0;
   1687 	else if (cs->tracks[track].indices[1].number == 1)
   1688 		return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
   1689 	else
   1690 		return 0;
   1691 }
   1692 
   1693 static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
   1694 {
   1695 	FLAC__uint32 n = 0;
   1696 	while (x) {
   1697 		n += (x%10);
   1698 		x /= 10;
   1699 	}
   1700 	return n;
   1701 }
   1702 
   1703 /*@@@@add to tests*/
   1704 FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
   1705 {
   1706 	const FLAC__StreamMetadata_CueSheet *cs;
   1707 
   1708 	FLAC__ASSERT(object != NULL);
   1709 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
   1710 
   1711 	cs = &object->data.cue_sheet;
   1712 
   1713 	if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
   1714 		return 0;
   1715 
   1716 	{
   1717 		FLAC__uint32 i, length, sum = 0;
   1718 		for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
   1719 			sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
   1720 		length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
   1721 
   1722 		return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
   1723 	}
   1724 }
   1725 
   1726 FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
   1727 {
   1728 	char *old;
   1729 	size_t old_length, new_length;
   1730 
   1731 	FLAC__ASSERT(object != NULL);
   1732 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
   1733 	FLAC__ASSERT(mime_type != NULL);
   1734 
   1735 	old = object->data.picture.mime_type;
   1736 	old_length = old? strlen(old) : 0;
   1737 	new_length = strlen(mime_type);
   1738 
   1739 	/* do the copy first so that if we fail we leave the object untouched */
   1740 	if (copy) {
   1741 		if (new_length >= SIZE_MAX) /* overflow check */
   1742 			return false;
   1743 		if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1))
   1744 			return false;
   1745 	}
   1746 	else {
   1747 		object->data.picture.mime_type = mime_type;
   1748 	}
   1749 
   1750 	free(old);
   1751 
   1752 	object->length -= old_length;
   1753 	object->length += new_length;
   1754 	return true;
   1755 }
   1756 
   1757 FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
   1758 {
   1759 	FLAC__byte *old;
   1760 	size_t old_length, new_length;
   1761 
   1762 	FLAC__ASSERT(object != NULL);
   1763 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
   1764 	FLAC__ASSERT(description != NULL);
   1765 
   1766 	old = object->data.picture.description;
   1767 	old_length = old? strlen((const char *)old) : 0;
   1768 	new_length = strlen((const char *)description);
   1769 
   1770 	/* do the copy first so that if we fail we leave the object untouched */
   1771 	if (copy) {
   1772 		if (new_length >= SIZE_MAX) /* overflow check */
   1773 			return false;
   1774 		if (!copy_bytes_(&object->data.picture.description, description, new_length+1))
   1775 			return false;
   1776 	}
   1777 	else {
   1778 		object->data.picture.description = description;
   1779 	}
   1780 
   1781 	free(old);
   1782 
   1783 	object->length -= old_length;
   1784 	object->length += new_length;
   1785 	return true;
   1786 }
   1787 
   1788 FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
   1789 {
   1790 	FLAC__byte *old;
   1791 
   1792 	FLAC__ASSERT(object != NULL);
   1793 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
   1794 	FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false));
   1795 
   1796 	old = object->data.picture.data;
   1797 
   1798 	/* do the copy first so that if we fail we leave the object untouched */
   1799 	if (copy) {
   1800 		if (!copy_bytes_(&object->data.picture.data, data, length))
   1801 			return false;
   1802 	}
   1803 	else {
   1804 		object->data.picture.data = data;
   1805 	}
   1806 
   1807 	free(old);
   1808 
   1809 	object->length -= object->data.picture.data_length;
   1810 	object->data.picture.data_length = length;
   1811 	object->length += length;
   1812 	return true;
   1813 }
   1814 
   1815 FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
   1816 {
   1817 	FLAC__ASSERT(object != NULL);
   1818 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
   1819 
   1820 	return FLAC__format_picture_is_legal(&object->data.picture, violation);
   1821 }
   1822