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_(©, 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