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