📄 metadata_iterators.c
字号:
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; } /* 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)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -