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