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