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