/* libFLAC - Free Lossless Audio Codec library * Copyright (C) 2001-2009 Josh Coalson * Copyright (C) 2011-2016 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Xiph.org Foundation nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdlib.h>#include <string.h> #include "private/metadata.h"#include "private/memory.h" #include "share/alloc.h"#include "share/compat.h" // 8bb: hide POSIX warnings#ifdef _MSC_VER#pragma warning(disable: 4996)#endif /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p /**************************************************************************** * * Local routines * ***************************************************************************/ /* copy bytes: * from = NULL && bytes = 0 * to <- NULL * from != NULL && bytes > 0 * to <- copy of from * else ASSERT * malloc error leaves 'to' unchanged */static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes){ if (bytes > 0 && from != NULL) { FLAC__byte *x; if ((x = safe_malloc_(bytes)) == NULL) return false; memcpy(x, from, bytes); *to = x; } else { *to = 0; } return true;} /* reallocate entry to 1 byte larger and add a terminating NUL *//* realloc() failure leaves entry unchanged */static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length){ FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1); if (x != NULL) { x[length] = '\0'; *entry = x; return true; } else return false;} /* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' * unchanged if malloc fails, free()ing the original '*to' if it * succeeds and the original '*to' was not NULL */static FLAC__bool copy_cstring_(char **to, const char *from){ char *copy = strdup(from); if (copy) { free(*to); *to = copy; return true; } else return false;} static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from){ to->length = from->length; if (from->entry == 0) { to->entry = 0; } else { FLAC__byte *x; if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL) return false; memcpy(x, from->entry, from->length); x[from->length] = '\0'; to->entry = x; } return true;} static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from){ memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); if (from->indices == 0) { } else { FLAC__StreamMetadata_CueSheet_Index *x; if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL) return false; memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); to->indices = x; } return true;} static void seektable_calculate_length_(FLAC__StreamMetadata *object){ object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;} static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points){ FLAC__StreamMetadata_SeekPoint *object_array; object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); if (object_array != NULL) { uint32_t i; for (i = 0; i < num_points; i++) { object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; object_array[i].stream_offset = 0; object_array[i].frame_samples = 0; } } return object_array;} static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object){ uint32_t i; object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; object->length += object->data.vorbis_comment.vendor_string.length; object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); object->length += object->data.vorbis_comment.comments[i].length; }} static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments){ return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));} static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments){ uint32_t i; for (i = 0; i < num_comments; i++) free(object_array[i].entry); free(object_array);} static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments){ FLAC__StreamMetadata_VorbisComment_Entry *return_array; return_array = vorbiscomment_entry_array_new_(num_comments); if (return_array != NULL) { uint32_t i; for (i = 0; i < num_comments; i++) { if (!copy_vcentry_(return_array+i, object_array+i)) { vorbiscomment_entry_array_delete_(return_array, num_comments); return 0; } } } return return_array;} static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy){ FLAC__byte *save; save = dest->entry; if (src->entry != NULL) { if (copy) { /* do the copy first so that if we fail we leave the dest object untouched */ if (!copy_vcentry_(dest, src)) return false; } else { /* we have to make sure that the string we're taking over is null-terminated */ /* * Stripping the const from src->entry is OK since we're taking * ownership of the pointer. This is a hack around a deficiency * in the API where the same function is used for 'copy' and * 'own', but the source entry is a const pointer. If we were * precise, the 'own' flavor would be a separate function with a * non-const source pointer. But it's not, so we hack away. */ if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) return false; *dest = *src; } } else { /* the src is null */ *dest = *src; } free(save); vorbiscomment_calculate_length_(object); return true;} static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length){ uint32_t i; for (i = offset; i < object->data.vorbis_comment.num_comments; i++) { if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) return (int)i; } return -1;} static void cuesheet_calculate_length_(FLAC__StreamMetadata *object){ uint32_t i; object->length = ( FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN ) / 8; object->length += object->data.cue_sheet.num_tracks * ( FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN ) / 8; for (i = 0; i < object->data.cue_sheet.num_tracks; i++) { object->length += object->data.cue_sheet.tracks[i].num_indices * ( FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN ) / 8; }} static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices){ return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));} static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks){ return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));} static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks){ uint32_t i; for (i = 0; i < num_tracks; i++) { if (object_array[i].indices != 0) { free(object_array[i].indices); } } free(object_array);} static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks){ FLAC__StreamMetadata_CueSheet_Track *return_array; return_array = cuesheet_track_array_new_(num_tracks); if (return_array != NULL) { uint32_t i; for (i = 0; i < num_tracks; i++) { if (!copy_track_(return_array+i, object_array+i)) { cuesheet_track_array_delete_(return_array, num_tracks); return 0; } } } return return_array;} static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy){ FLAC__StreamMetadata_CueSheet_Index *save; save = dest->indices; /* do the copy first so that if we fail we leave the object untouched */ if (copy) { if (!copy_track_(dest, src)) return false; } else { *dest = *src; } free(save); cuesheet_calculate_length_(object); return true;} /**************************************************************************** * * Metadata object routines * ***************************************************************************/ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type){ FLAC__StreamMetadata *object; if (type > FLAC__MAX_METADATA_TYPE) return 0; object = calloc(1, sizeof(FLAC__StreamMetadata)); if (object != NULL) { object->is_last = false; object->type = type; switch(type) { case FLAC__METADATA_TYPE_STREAMINFO: object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; break; case FLAC__METADATA_TYPE_PADDING: /* calloc() took care of this for us: object->length = 0; */ break; case FLAC__METADATA_TYPE_APPLICATION: object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; /* calloc() took care of this for us: object->data.application.data = 0; */ break; case FLAC__METADATA_TYPE_SEEKTABLE: /* calloc() took care of this for us: object->length = 0; object->data.seek_table.num_points = 0; object->data.seek_table.points = 0; */ break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING); if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { free(object); return 0; } vorbiscomment_calculate_length_(object); break; case FLAC__METADATA_TYPE_CUESHEET: cuesheet_calculate_length_(object); break; case FLAC__METADATA_TYPE_PICTURE: object->length = ( FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + 0 /* no data */ ) / 8; object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; object->data.picture.mime_type = 0; object->data.picture.description = 0; /* calloc() took care of this for us: object->data.picture.width = 0; object->data.picture.height = 0; object->data.picture.depth = 0; object->data.picture.colors = 0; object->data.picture.data_length = 0; object->data.picture.data = 0; */ /* now initialize mime_type and description with empty strings to make things easier on the client */ if (!copy_cstring_(&object->data.picture.mime_type, "")) { free(object); return 0; } if (!copy_cstring_((char**)(&object->data.picture.description), "")) { free(object->data.picture.mime_type); free(object); return 0; } break; default: /* calloc() took care of this for us: object->length = 0; object->data.unknown.data = 0; */ break; } } return object;} FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object){ FLAC__StreamMetadata *to; if ((to = FLAC__metadata_object_new(object->type)) != NULL) { to->is_last = object->is_last; to->type = object->type; to->length = object->length; switch(to->type) { case FLAC__METADATA_TYPE_STREAMINFO: memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); break; case FLAC__METADATA_TYPE_PADDING: break; case FLAC__METADATA_TYPE_APPLICATION: if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */ FLAC__metadata_object_delete(to); return 0; } memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { FLAC__metadata_object_delete(to); return 0; } break; case FLAC__METADATA_TYPE_SEEKTABLE: to->data.seek_table.num_points = object->data.seek_table.num_points; if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */ FLAC__metadata_object_delete(to); return 0; } 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))) { FLAC__metadata_object_delete(to); return 0; } break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: if (to->data.vorbis_comment.vendor_string.entry != NULL) { free(to->data.vorbis_comment.vendor_string.entry); to->data.vorbis_comment.vendor_string.entry = 0; } if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { FLAC__metadata_object_delete(to); return 0; }Lines 1–500 of 1588. Load more
/* libFLAC - Free Lossless Audio Codec library * Copyright (C) 2001-2009 Josh Coalson * Copyright (C) 2011-2016 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Xiph.org Foundation nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdlib.h> #include <string.h> #include "private/metadata.h" #include "private/memory.h" #include "share/alloc.h" #include "share/compat.h" // 8bb: hide POSIX warnings #ifdef _MSC_VER #pragma warning(disable: 4996) #endif /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ #define safe_malloc_mul_2op_ safe_malloc_mul_2op_p /**************************************************************************** * * Local routines * ***************************************************************************/ /* copy bytes: * from = NULL && bytes = 0 * to <- NULL * from != NULL && bytes > 0 * to <- copy of from * else ASSERT * malloc error leaves 'to' unchanged */ static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) { if (bytes > 0 && from != NULL) { FLAC__byte *x; if ((x = safe_malloc_(bytes)) == NULL) return false; memcpy(x, from, bytes); *to = x; } else { *to = 0; } return true; } /* reallocate entry to 1 byte larger and add a terminating NUL */ /* realloc() failure leaves entry unchanged */ static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length) { FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1); if (x != NULL) { x[length] = '\0'; *entry = x; return true; } else return false; } /* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' * unchanged if malloc fails, free()ing the original '*to' if it * succeeds and the original '*to' was not NULL */ static FLAC__bool copy_cstring_(char **to, const char *from) { char *copy = strdup(from); if (copy) { free(*to); *to = copy; return true; } else return false; } static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) { to->length = from->length; if (from->entry == 0) { to->entry = 0; } else { FLAC__byte *x; if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL) return false; memcpy(x, from->entry, from->length); x[from->length] = '\0'; to->entry = x; } return true; } static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from) { memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); if (from->indices == 0) { } else { FLAC__StreamMetadata_CueSheet_Index *x; if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL) return false; memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); to->indices = x; } return true; } static void seektable_calculate_length_(FLAC__StreamMetadata *object) { object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; } static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points) { FLAC__StreamMetadata_SeekPoint *object_array; object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); if (object_array != NULL) { uint32_t i; for (i = 0; i < num_points; i++) { object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; object_array[i].stream_offset = 0; object_array[i].frame_samples = 0; } } return object_array; } static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object) { uint32_t i; object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; object->length += object->data.vorbis_comment.vendor_string.length; object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); object->length += object->data.vorbis_comment.comments[i].length; } } static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments) { return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); } static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) { uint32_t i; for (i = 0; i < num_comments; i++) free(object_array[i].entry); free(object_array); } static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) { FLAC__StreamMetadata_VorbisComment_Entry *return_array; return_array = vorbiscomment_entry_array_new_(num_comments); if (return_array != NULL) { uint32_t i; for (i = 0; i < num_comments; i++) { if (!copy_vcentry_(return_array+i, object_array+i)) { vorbiscomment_entry_array_delete_(return_array, num_comments); return 0; } } } return return_array; } static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy) { FLAC__byte *save; save = dest->entry; if (src->entry != NULL) { if (copy) { /* do the copy first so that if we fail we leave the dest object untouched */ if (!copy_vcentry_(dest, src)) return false; } else { /* we have to make sure that the string we're taking over is null-terminated */ /* * Stripping the const from src->entry is OK since we're taking * ownership of the pointer. This is a hack around a deficiency * in the API where the same function is used for 'copy' and * 'own', but the source entry is a const pointer. If we were * precise, the 'own' flavor would be a separate function with a * non-const source pointer. But it's not, so we hack away. */ if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) return false; *dest = *src; } } else { /* the src is null */ *dest = *src; } free(save); vorbiscomment_calculate_length_(object); return true; } static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length) { uint32_t i; for (i = offset; i < object->data.vorbis_comment.num_comments; i++) { if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) return (int)i; } return -1; } static void cuesheet_calculate_length_(FLAC__StreamMetadata *object) { uint32_t i; object->length = ( FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN ) / 8; object->length += object->data.cue_sheet.num_tracks * ( FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN ) / 8; for (i = 0; i < object->data.cue_sheet.num_tracks; i++) { object->length += object->data.cue_sheet.tracks[i].num_indices * ( FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN ) / 8; } } static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices) { return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); } static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks) { return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); } static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) { uint32_t i; for (i = 0; i < num_tracks; i++) { if (object_array[i].indices != 0) { free(object_array[i].indices); } } free(object_array); } static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) { FLAC__StreamMetadata_CueSheet_Track *return_array; return_array = cuesheet_track_array_new_(num_tracks); if (return_array != NULL) { uint32_t i; for (i = 0; i < num_tracks; i++) { if (!copy_track_(return_array+i, object_array+i)) { cuesheet_track_array_delete_(return_array, num_tracks); return 0; } } } return return_array; } static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy) { FLAC__StreamMetadata_CueSheet_Index *save; save = dest->indices; /* do the copy first so that if we fail we leave the object untouched */ if (copy) { if (!copy_track_(dest, src)) return false; } else { *dest = *src; } free(save); cuesheet_calculate_length_(object); return true; } /**************************************************************************** * * Metadata object routines * ***************************************************************************/ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type) { FLAC__StreamMetadata *object; if (type > FLAC__MAX_METADATA_TYPE) return 0; object = calloc(1, sizeof(FLAC__StreamMetadata)); if (object != NULL) { object->is_last = false; object->type = type; switch(type) { case FLAC__METADATA_TYPE_STREAMINFO: object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; break; case FLAC__METADATA_TYPE_PADDING: /* calloc() took care of this for us: object->length = 0; */ break; case FLAC__METADATA_TYPE_APPLICATION: object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; /* calloc() took care of this for us: object->data.application.data = 0; */ break; case FLAC__METADATA_TYPE_SEEKTABLE: /* calloc() took care of this for us: object->length = 0; object->data.seek_table.num_points = 0; object->data.seek_table.points = 0; */ break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING); if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { free(object); return 0; } vorbiscomment_calculate_length_(object); break; case FLAC__METADATA_TYPE_CUESHEET: cuesheet_calculate_length_(object); break; case FLAC__METADATA_TYPE_PICTURE: object->length = ( FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + 0 /* no data */ ) / 8; object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; object->data.picture.mime_type = 0; object->data.picture.description = 0; /* calloc() took care of this for us: object->data.picture.width = 0; object->data.picture.height = 0; object->data.picture.depth = 0; object->data.picture.colors = 0; object->data.picture.data_length = 0; object->data.picture.data = 0; */ /* now initialize mime_type and description with empty strings to make things easier on the client */ if (!copy_cstring_(&object->data.picture.mime_type, "")) { free(object); return 0; } if (!copy_cstring_((char**)(&object->data.picture.description), "")) { free(object->data.picture.mime_type); free(object); return 0; } break; default: /* calloc() took care of this for us: object->length = 0; object->data.unknown.data = 0; */ break; } } return object; } FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object) { FLAC__StreamMetadata *to; if ((to = FLAC__metadata_object_new(object->type)) != NULL) { to->is_last = object->is_last; to->type = object->type; to->length = object->length; switch(to->type) { case FLAC__METADATA_TYPE_STREAMINFO: memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); break; case FLAC__METADATA_TYPE_PADDING: break; case FLAC__METADATA_TYPE_APPLICATION: if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */ FLAC__metadata_object_delete(to); return 0; } memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { FLAC__metadata_object_delete(to); return 0; } break; case FLAC__METADATA_TYPE_SEEKTABLE: to->data.seek_table.num_points = object->data.seek_table.num_points; if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */ FLAC__metadata_object_delete(to); return 0; } 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))) { FLAC__metadata_object_delete(to); return 0; } break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: if (to->data.vorbis_comment.vendor_string.entry != NULL) { free(to->data.vorbis_comment.vendor_string.entry); to->data.vorbis_comment.vendor_string.entry = 0; } if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { FLAC__metadata_object_delete(to); return 0; }