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