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