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