1588 lines · 53.4 KB · C
RawDownload
/* 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t