📄 metadata_iterators.c
字号:
/* write the metadata */
for(node = chain->head; node; node = node->next) {
if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
return false;
}
if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
return false;
}
}
/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
/* copy the file postfix (everything after the metadata) */
if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
return false;
}
if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
chain->status = get_equivalent_status_(status);
return false;
}
return true;
}
FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new()
{
FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
if(0 != chain)
chain_init_(chain);
return chain;
}
FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
{
FLAC__ASSERT(0 != chain);
chain_clear_(chain);
free(chain);
}
FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
{
FLAC__Metadata_ChainStatus status;
FLAC__ASSERT(0 != chain);
status = chain->status;
chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
return status;
}
FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
{
FILE *file;
FLAC__bool ret;
FLAC__ASSERT(0 != chain);
FLAC__ASSERT(0 != filename);
chain_clear_(chain);
if(0 == (chain->filename = _strdup(filename))) {
chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
return false;
}
if(0 == (file = fopen(filename, "rb"))) {
chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
return false;
}
/* chain_read_cb_() sets chain->status for us */
ret = chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_);
fclose(file);
return ret;
}
FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
{
FLAC__ASSERT(0 != chain);
chain_clear_(chain);
if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
return false;
}
/* rewind */
if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
return false;
}
if(!chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell))
return false; /* chain->status is already set by chain_read_cb_ */
return true;
}
FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
{
/* This does all the same checks that are in chain_prepare_for_write_()
* but doesn't actually alter the chain. Make sure to update the logic
* here if chain_prepare_for_write_() changes.
*/
const unsigned current_length = chain_calculate_length_(chain);
FLAC__ASSERT(0 != 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)
return false;
/* 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)
return false;
/* 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)
return false;
/* if there is at least 'delta' bytes of padding, trim the padding down */
else if(chain->tail->data->length >= delta)
return false;
}
}
}
return (current_length != chain->initial_length);
}
FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
{
const char *tempfile_path_prefix = 0;
unsigned current_length;
FLAC__ASSERT(0 != chain);
if (0 == chain->filename) {
chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
return false;
}
current_length = chain_prepare_for_write_(chain, use_padding);
/* a return value of 0 means there was an error; chain->status is already set */
if (0 == current_length)
return false;
if(current_length == chain->initial_length) {
if(!chain_rewrite_metadata_in_place_(chain))
return false;
}
else {
if(!chain_rewrite_file_(chain, tempfile_path_prefix))
return false;
/* recompute lengths and offsets */
{
const FLAC__Metadata_Node *node;
chain->initial_length = current_length;
chain->last_offset = chain->first_offset;
for(node = chain->head; node; node = node->next)
chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
}
}
return true;
}
FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
{
unsigned current_length;
FLAC__ASSERT(0 != chain);
if (0 != chain->filename) {
chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
return false;
}
if (0 == callbacks.write || 0 == callbacks.seek) {
chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
return false;
}
if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
return false;
}
current_length = chain_prepare_for_write_(chain, use_padding);
/* a return value of 0 means there was an error; chain->status is already set */
if (0 == current_length)
return false;
FLAC__ASSERT(current_length == chain->initial_length);
return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
}
FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
{
unsigned current_length;
FLAC__ASSERT(0 != chain);
if (0 != chain->filename) {
chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
return false;
}
if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
return false;
}
if (0 == temp_callbacks.write) {
chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
return false;
}
if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
return false;
}
current_length = chain_prepare_for_write_(chain, use_padding);
/* a return value of 0 means there was an error; chain->status is already set */
if (0 == current_length)
return false;
FLAC__ASSERT(current_length != chain->initial_length);
/* rewind */
if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
return false;
}
if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
return false;
/* recompute lengths and offsets */
{
const FLAC__Metadata_Node *node;
chain->initial_length = current_length;
chain->last_offset = chain->first_offset;
for(node = chain->head; node; node = node->next)
chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
}
return true;
}
FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
{
FLAC__Metadata_Node *node;
FLAC__ASSERT(0 != chain);
for(node = chain->head; node; ) {
if(!chain_merge_adjacent_padding_(chain, node))
node = node->next;
}
}
FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
{
FLAC__Metadata_Node *node, *save;
unsigned i;
FLAC__ASSERT(0 != chain);
/*
* Don't try and be too smart... this simple algo is good enough for
* the small number of nodes that we deal with.
*/
for(i = 0, node = chain->head; i < chain->nodes; i++) {
if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
save = node->next;
chain_remove_node_(chain, node);
chain_append_node_(chain, node);
node = save;
}
else {
node = node->next;
}
}
FLAC__metadata_chain_merge_padding(chain);
}
FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new()
{
FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
/* calloc() implies:
iterator->current = 0;
iterator->chain = 0;
*/
return iterator;
}
FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
{
FLAC__ASSERT(0 != iterator);
free(iterator);
}
FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
{
FLAC__ASSERT(0 != iterator);
FLAC__ASSERT(0 != chain);
FLAC__ASSERT(0 != chain->head);
iterator->chain = chain;
iterator->current = chain->head;
}
FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
{
FLAC__ASSERT(0 != iterator);
if(0 == iterator->current || 0 == iterator->current->next)
return false;
iterator->current = iterator->current->next;
return true;
}
FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
{
FLAC__ASSERT(0 != iterator);
if(0 == iterator->current || 0 == iterator->current->prev)
return false;
iterator->current = iterator->current->prev;
return true;
}
FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
{
FLAC__ASSERT(0 != iterator);
FLAC__ASSERT(0 != iterator->current);
FLAC__ASSERT(0 != iterator->current->data);
return iterator->current->data->type;
}
FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
{
FLAC__ASSERT(0 != iterator);
FLAC__ASSERT(0 != iterator->current);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -