metadata_object.c

来自「这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔」· C语言 代码 · 共 1,474 行 · 第 1/4 页

C
1,474
字号
/* libFLAC - Free Lossless Audio Codec library
 * Copyright (C) 2001,2002,2003,2004,2005  Josh Coalson
 *
 * 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 "FLAC/assert.h"

/****************************************************************************
 *
 * Local routines
 *
 ***************************************************************************/

static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
{
	if(bytes > 0 && 0 != from) {
		FLAC__byte *x;
		if(0 == (x = (FLAC__byte*)malloc(bytes)))
			return false;
		memcpy(x, from, bytes);
		*to = x;
	}
	else {
		FLAC__ASSERT(0 == from);
		FLAC__ASSERT(bytes == 0);
		*to = 0;
	}
	return true;
}

static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
{
	FLAC__byte *x = (FLAC__byte*)realloc(*entry, length+1);
	if(0 != x) {
		x[length] = '\0';
		*entry = x;
		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(0 == from->entry) {
		FLAC__ASSERT(from->length == 0);
		to->entry = 0;
	}
	else {
		FLAC__byte *x;
		FLAC__ASSERT(from->length > 0);
		if(0 == (x = (FLAC__byte*)malloc(from->length+1)))
			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(0 == from->indices) {
		FLAC__ASSERT(from->num_indices == 0);
	}
	else {
		FLAC__StreamMetadata_CueSheet_Index *x;
		FLAC__ASSERT(from->num_indices > 0);
		if(0 == (x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index))))
			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)
{
	FLAC__ASSERT(0 != object);
	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);

	object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
}

static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
{
	FLAC__StreamMetadata_SeekPoint *object_array;

	FLAC__ASSERT(num_points > 0);

	object_array = (FLAC__StreamMetadata_SeekPoint*)malloc(num_points * sizeof(FLAC__StreamMetadata_SeekPoint));

	if(0 != object_array) {
		unsigned 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)
{
	unsigned i;

	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);

	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_(unsigned num_comments)
{
	FLAC__ASSERT(num_comments > 0);

	return (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
}

static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
{
	unsigned i;

	FLAC__ASSERT(0 != object_array && num_comments > 0);

	for(i = 0; i < num_comments; i++)
		if(0 != object_array[i].entry)
			free(object_array[i].entry);

	if(0 != object_array)
		free(object_array);
}

static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
{
	FLAC__StreamMetadata_VorbisComment_Entry *return_array;

	FLAC__ASSERT(0 != object_array);
	FLAC__ASSERT(num_comments > 0);

	return_array = vorbiscomment_entry_array_new_(num_comments);

	if(0 != return_array) {
		unsigned 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;

	FLAC__ASSERT(0 != object);
	FLAC__ASSERT(0 != dest);
	FLAC__ASSERT(0 != src);
	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
	FLAC__ASSERT((0 != src->entry && src->length > 0) || (0 == src->entry && src->length == 0));

	save = dest->entry;

	if(0 != src->entry && src->length > 0) {
		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;
	}

	if(0 != save)
		free(save);

	vorbiscomment_calculate_length_(object);
	return true;
}

static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
{
	unsigned i;

	FLAC__ASSERT(0 != object);
	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
	FLAC__ASSERT(0 != field_name);

	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)
{
	unsigned i;

	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);

	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_(unsigned num_indices)
{
	FLAC__ASSERT(num_indices > 0);

	return (FLAC__StreamMetadata_CueSheet_Index*)calloc(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
}

static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
{
	FLAC__ASSERT(num_tracks > 0);

	return (FLAC__StreamMetadata_CueSheet_Track*)calloc(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
}

static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
{
	unsigned i;

	FLAC__ASSERT(0 != object_array && num_tracks > 0);

	for(i = 0; i < num_tracks; i++) {
		if(0 != object_array[i].indices) {
			FLAC__ASSERT(object_array[i].num_indices > 0);
			free(object_array[i].indices);
		}
	}

	if(0 != object_array)
		free(object_array);
}

static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
{
	FLAC__StreamMetadata_CueSheet_Track *return_array;

	FLAC__ASSERT(0 != object_array);
	FLAC__ASSERT(num_tracks > 0);

	return_array = cuesheet_track_array_new_(num_tracks);

	if(0 != return_array) {
		unsigned 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;

	FLAC__ASSERT(0 != object);
	FLAC__ASSERT(0 != dest);
	FLAC__ASSERT(0 != src);
	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
	FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0));

	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;
	}

	if(0 != save)
		free(save);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?