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