⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 metadata_iterators.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 5 页
字号:
	FLAC__ASSERT(0 != chain);
	FLAC__ASSERT(0 != node);

	if(node == chain->head)
		chain->head = node->next;
	else
		node->prev->next = node->next;

	if(node == chain->tail)
		chain->tail = node->prev;
	else
		node->next->prev = node->prev;

	if(0 != chain->tail)
		chain->tail->data->is_last = true;

	chain->nodes--;
}

static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
{
	chain_remove_node_(chain, node);
	node_delete_(node);
}

static unsigned chain_calculate_length_(FLAC__Metadata_Chain *chain)
{
	const FLAC__Metadata_Node *node;
	unsigned length = 0;
	for(node = chain->head; node; node = node->next)
		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
	return length;
}

static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
{
	FLAC__ASSERT(0 != node);
	FLAC__ASSERT(0 != node->data);
	FLAC__ASSERT(0 != iterator);
	FLAC__ASSERT(0 != iterator->current);
	FLAC__ASSERT(0 != iterator->chain);
	FLAC__ASSERT(0 != iterator->chain->head);
	FLAC__ASSERT(0 != iterator->chain->tail);

	node->data->is_last = false;

	node->prev = iterator->current->prev;
	node->next = iterator->current;

	if(0 == node->prev)
		iterator->chain->head = node;
	else
		node->prev->next = node;

	iterator->current->prev = node;

	iterator->chain->nodes++;
}

static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
{
	FLAC__ASSERT(0 != node);
	FLAC__ASSERT(0 != node->data);
	FLAC__ASSERT(0 != iterator);
	FLAC__ASSERT(0 != iterator->current);
	FLAC__ASSERT(0 != iterator->chain);
	FLAC__ASSERT(0 != iterator->chain->head);
	FLAC__ASSERT(0 != iterator->chain->tail);

	iterator->current->data->is_last = false;

	node->prev = iterator->current;
	node->next = iterator->current->next;

	if(0 == node->next)
		iterator->chain->tail = node;
	else
		node->next->prev = node;

	node->prev->next = node;

	iterator->chain->tail->data->is_last = true;

	iterator->chain->nodes++;
}

/* return true iff node and node->next are both padding */
static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
{
	if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
		const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
		node->data->length += growth;

		chain_delete_node_(chain, node->next);
		return true;
	}
	else
		return false;
}

/* Returns the new length of the chain, or 0 if there was an error. */
/* WATCHOUT: This can get called multiple times before a write, so
 * it should still work when this happens.
 */
/* WATCHOUT: Make sure to also update the logic in
 * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
 */
static unsigned chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
{
	unsigned current_length = chain_calculate_length_(chain);

	if(use_padding) {
		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
		if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
			const unsigned delta = chain->initial_length - current_length;
			chain->tail->data->length += delta;
			current_length += delta;
			FLAC__ASSERT(current_length == chain->initial_length);
		}
		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
		else if(current_length + FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
			FLAC__StreamMetadata *padding;
			FLAC__Metadata_Node *node;
			if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
				return 0;
			}
			padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
			if(0 == (node = node_new_())) {
				FLAC__metadata_object_delete(padding);
				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
				return 0;
			}
			node->data = padding;
			chain_append_node_(chain, node);
			current_length = chain_calculate_length_(chain);
			FLAC__ASSERT(current_length == chain->initial_length);
		}
		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
		else if(current_length > chain->initial_length) {
			const unsigned delta = current_length - chain->initial_length;
			if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
				/* if the delta is exactly the size of the last padding block, remove the padding block */
				if(chain->tail->data->length + FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
					chain_delete_node_(chain, chain->tail);
					current_length = chain_calculate_length_(chain);
					FLAC__ASSERT(current_length == chain->initial_length);
				}
				/* if there is at least 'delta' bytes of padding, trim the padding down */
				else if(chain->tail->data->length >= delta) {
					chain->tail->data->length -= delta;
					current_length -= delta;
					FLAC__ASSERT(current_length == chain->initial_length);
				}
			}
		}
	}

	return current_length;
}

static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
{
	FLAC__Metadata_Node *node;

	FLAC__ASSERT(0 != chain);

	/* we assume we're already at the beginning of the file */

	switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
		case 0:
			break;
		case 1:
			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
			return false;
		case 2:
			chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
			return false;
		case 3:
			chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
			return false;
		default:
			FLAC__ASSERT(0);
			return false;
	}

	{
		FLAC__int64 pos = tell_cb(handle);
		if(pos < 0) {
			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
			return false;
		}
		chain->first_offset = (long)pos;
	}

	{
		FLAC__bool is_last;
		FLAC__MetadataType type;
		unsigned length;

		do {
			node = node_new_();
			if(0 == node) {
				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
				return false;
			}

			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
				return false;
			}

			node->data = FLAC__metadata_object_new(type);
			if(0 == node->data) {
				node_delete_(node);
				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
				return false;
			}

			node->data->is_last = is_last;
			node->data->length = length;

			chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
			if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
				node_delete_(node);
				return false;
			}
			chain_append_node_(chain, node);
		} while(!is_last);
	}

	{
		FLAC__int64 pos = tell_cb(handle);
		if(pos < 0) {
			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
			return false;
		}
		chain->last_offset = (long)pos;
	}

	chain->initial_length = chain_calculate_length_(chain);

	return true;
}

static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
{
	FLAC__Metadata_Node *node;

	FLAC__ASSERT(0 != chain);
	FLAC__ASSERT(0 != chain->head);

	if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
		return false;
	}

	for(node = chain->head; node; node = node->next) {
		if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
			return false;
		}
		if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
			return false;
		}
	}

	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/

	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
	return true;
}

static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
{
	FILE *file;
	FLAC__bool ret;

	FLAC__ASSERT(0 != chain->filename);

	if(0 == (file = fopen(chain->filename, "r+b"))) {
		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
		return false;
	}

	/* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
	ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);

	fclose(file);

	return ret;
}

static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
{
	FILE *f, *tempfile;
	char *tempfilename;
	FLAC__Metadata_SimpleIteratorStatus status;
	const FLAC__Metadata_Node *node;

	FLAC__ASSERT(0 != chain);
	FLAC__ASSERT(0 != chain->filename);
	FLAC__ASSERT(0 != chain->head);

	/* copy the file prefix (data up to first metadata block */
	if(0 == (f = fopen(chain->filename, "rb"))) {
		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
		return false;
	}
	if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
		chain->status = get_equivalent_status_(status);
		cleanup_tempfile_(&tempfile, &tempfilename);
		return false;
	}
	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
		chain->status = get_equivalent_status_(status);
		cleanup_tempfile_(&tempfile, &tempfilename);
		return false;
	}

	/* write the metadata */
	for(node = chain->head; node; node = node->next) {
		if(!write_metadata_block_header_(tempfile, &status, node->data)) {
			chain->status = get_equivalent_status_(status);
			return false;
		}
		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
			chain->status = get_equivalent_status_(status);
			return false;
		}
	}
	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/

	/* copy the file postfix (everything after the metadata) */
	if(0 != fseek(f, chain->last_offset, SEEK_SET)) {
		cleanup_tempfile_(&tempfile, &tempfilename);
		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
		return false;
	}
	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
		cleanup_tempfile_(&tempfile, &tempfilename);
		chain->status = get_equivalent_status_(status);
		return false;
	}

	/* move the tempfile on top of the original */
	(void)fclose(f);
	if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
		return false;

	return true;
}

/* assumes 'handle' is already at beginning of file */
static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
{
	FLAC__Metadata_SimpleIteratorStatus status;
	const FLAC__Metadata_Node *node;

	FLAC__ASSERT(0 != chain);
	FLAC__ASSERT(0 == chain->filename);
	FLAC__ASSERT(0 != chain->head);

	/* copy the file prefix (data up to first metadata block */
	if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
		chain->status = get_equivalent_status_(status);
		return false;
	}

⌨️ 快捷键说明

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