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