add callback-based versions of chain writing: FLAC__metadata_chain_check_if_tempfile_needed(), FLAC__metadata_chain_write_with_callbacks(), FLAC__metadata_chain_write_with_callbacks_and_tempfile()
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
index 19bf015..9feaeae 100644
--- a/src/libFLAC/metadata_iterators.c
+++ b/src/libFLAC/metadata_iterators.c
@@ -88,20 +88,20 @@
static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_streaminfo_(FILE *file, const FLAC__StreamMetadata_StreamInfo *block);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_padding_(FILE *file, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_application_(FILE *file, const FLAC__StreamMetadata_Application *block, unsigned block_length);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_seektable_(FILE *file, const FLAC__StreamMetadata_SeekTable *block);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_vorbis_comment_(FILE *file, const FLAC__StreamMetadata_VorbisComment *block);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_cuesheet_(FILE *file, const FLAC__StreamMetadata_CueSheet *block);
-static FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_unknown_(FILE *file, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
-static FLAC__bool chain_rewrite_chain_(FLAC__Metadata_Chain *chain);
-static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix);
-
static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
@@ -113,7 +113,9 @@
static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup);
static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status);
static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status);
static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
@@ -773,7 +775,9 @@
"FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
"FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
"FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
- "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS"
+ "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+ "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+ "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
};
@@ -943,6 +947,67 @@
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__IOCallback_Close close_cb)
{
FLAC__Metadata_Node *node;
@@ -1029,6 +1094,164 @@
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__IOCallback_Close close_cb)
+{
+ FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != chain->head);
+
+ if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+ (void)close_cb(handle);
+ 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)) {
+ (void)close_cb(handle);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+ (void)close_cb(handle);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+
+ (void)close_cb(handle);
+
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+ FILE *file;
+
+ 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 and closes the file for us */
+ return chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_, (FLAC__IOCallback_Close)fclose);
+}
+
+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;
+}
+
+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__IOCallback_Close close_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__IOCallback_Close temp_close_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)) {
+ (void)temp_close_cb(temp_handle);
+ 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)) {
+ (void)temp_close_cb(temp_handle);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+ (void)temp_close_cb(temp_handle);
+ 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)) {
+ (void)temp_close_cb(temp_handle);
+ 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)) {
+ (void)temp_close_cb(temp_handle);
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+
+ (void)close_cb(handle);
+ (void)temp_close_cb(temp_handle);
+
+ return true;
+}
+
FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new()
{
FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
@@ -1088,8 +1311,6 @@
FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
{
- FILE *file;
-
FLAC__ASSERT(0 != chain);
chain_clear_(chain);
@@ -1105,6 +1326,40 @@
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 true;
+}
+
FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
{
struct stat stats;
@@ -1113,67 +1368,117 @@
FLAC__ASSERT(0 != chain);
- current_length = chain_calculate_length_(chain);
-
- if(use_padding) {
- 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);
- }
- 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 false;
- }
- 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 false;
- }
- node->data = padding;
- chain_append_node_(chain, node);
- current_length = chain_calculate_length_(chain);
- FLAC__ASSERT(current_length == chain->initial_length);
- }
- 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(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);
- }
- else if(chain->tail->data->length >= delta) {
- chain->tail->data->length -= delta;
- current_length -= delta;
- FLAC__ASSERT(current_length == chain->initial_length);
- }
- }
- }
+ 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(preserve_file_stats)
get_file_stats_(chain->filename, &stats);
if(current_length == chain->initial_length) {
- if(!chain_rewrite_chain_(chain))
+ 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);
+ }
}
if(preserve_file_stats)
set_file_stats_(chain->filename, &stats);
- /* recompute lengths and offsets if necessary */
- if(chain->initial_length != current_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 || 0 == callbacks.close) {
+ 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);
+
+ if(!chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek, callbacks.close))
+ return false;
+
+ return true;
+}
+
+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 || 0 == callbacks.close) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+ if (0 == temp_callbacks.write || 0 == callbacks.close) {
+ 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);
+
+ if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, callbacks.close, temp_handle, temp_callbacks.write, temp_callbacks.close))
+ return false;
+
+ /* recompute lengths and offsets */
+ {
const FLAC__Metadata_Node *node;
chain->initial_length = current_length;
chain->last_offset = chain->first_offset;
@@ -1784,16 +2089,10 @@
FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
{
- FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
-
FLAC__ASSERT(0 != file);
FLAC__ASSERT(0 != status);
- FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
- buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
- pack_uint32_(block->length, buffer + 1, 3);
-
- if(local__fwrite(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, file) != FLAC__STREAM_METADATA_HEADER_LENGTH) {
+ if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
return false;
}
@@ -1806,40 +2105,59 @@
FLAC__ASSERT(0 != file);
FLAC__ASSERT(0 != status);
- switch(block->type) {
- case FLAC__METADATA_TYPE_STREAMINFO:
- *status = write_metadata_block_data_streaminfo_(file, &block->data.stream_info);
- break;
- case FLAC__METADATA_TYPE_PADDING:
- *status = write_metadata_block_data_padding_(file, &block->data.padding, block->length);
- break;
- case FLAC__METADATA_TYPE_APPLICATION:
- *status = write_metadata_block_data_application_(file, &block->data.application, block->length);
- break;
- case FLAC__METADATA_TYPE_SEEKTABLE:
- *status = write_metadata_block_data_seektable_(file, &block->data.seek_table);
- break;
- case FLAC__METADATA_TYPE_VORBIS_COMMENT:
- *status = write_metadata_block_data_vorbis_comment_(file, &block->data.vorbis_comment);
- break;
- case FLAC__METADATA_TYPE_CUESHEET:
- *status = write_metadata_block_data_cuesheet_(file, &block->data.cue_sheet);
- break;
- default:
- *status = write_metadata_block_data_unknown_(file, &block->data.unknown, block->length);
- break;
+ if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
- return (*status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+ else {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_streaminfo_(FILE *file, const FLAC__StreamMetadata_StreamInfo *block)
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+ FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+
+ buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+ pack_uint32_(block->length, buffer + 1, 3);
+
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != block);
+
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+ default:
+ return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
+ }
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
{
FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
const unsigned channels1 = block->channels - 1;
const unsigned bps1 = block->bits_per_sample - 1;
- FLAC__ASSERT(0 != file);
-
/* we are using hardcoded numbers for simplicity but we should
* probably eventually write a bit-level packer and use the
* _STREAMINFO_ constants.
@@ -1855,72 +2173,66 @@
pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
memcpy(buffer+18, block->md5sum, 16);
- if(local__fwrite(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, file) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+ return false;
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_padding_(FILE *file, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
{
unsigned i, n = block_length;
FLAC__byte buffer[1024];
- FLAC__ASSERT(0 != file);
-
(void)block;
memset(buffer, 0, 1024);
for(i = 0; i < n/1024; i++)
- if(local__fwrite(buffer, 1, 1024, file) != 1024)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, 1024, handle) != 1024)
+ return false;
n %= 1024;
- if(local__fwrite(buffer, 1, n, file) != n)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, n, handle) != n)
+ return false;
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_application_(FILE *file, const FLAC__StreamMetadata_Application *block, unsigned block_length)
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length)
{
const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
- FLAC__ASSERT(0 != file);
-
- if(local__fwrite(block->id, 1, id_bytes, file) != id_bytes)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+ return false;
block_length -= id_bytes;
- if(local__fwrite(block->data, 1, block_length, file) != block_length)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(block->data, 1, block_length, handle) != block_length)
+ return false;
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_seektable_(FILE *file, const FLAC__StreamMetadata_SeekTable *block)
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
{
unsigned i;
FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
- FLAC__ASSERT(0 != file);
-
for(i = 0; i < block->num_points; i++) {
/* some MAGIC NUMBERs here */
pack_uint64_(block->points[i].sample_number, buffer, 8);
pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
- if(local__fwrite(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, file) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+ return false;
}
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_vorbis_comment_(FILE *file, const FLAC__StreamMetadata_VorbisComment *block)
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
{
unsigned i;
const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
@@ -1928,30 +2240,29 @@
FLAC__byte buffer[4]; /* magic number is asserted below */
FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == 4);
- FLAC__ASSERT(0 != file);
pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
- if(local__fwrite(buffer, 1, entry_length_len, file) != entry_length_len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
- if(local__fwrite(block->vendor_string.entry, 1, block->vendor_string.length, file) != block->vendor_string.length)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return false;
+ if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+ return false;
pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
- if(local__fwrite(buffer, 1, num_comments_len, file) != num_comments_len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+ return false;
for(i = 0; i < block->num_comments; i++) {
pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
- if(local__fwrite(buffer, 1, entry_length_len, file) != entry_length_len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
- if(local__fwrite(block->comments[i].entry, 1, block->comments[i].length, file) != block->comments[i].length)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return false;
+ if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+ return false;
}
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_cuesheet_(FILE *file, const FLAC__StreamMetadata_CueSheet *block)
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
{
unsigned i, j, len;
FLAC__byte buffer[1024]; /* asserted below that this is big enough */
@@ -1961,32 +2272,30 @@
FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
- FLAC__ASSERT(0 != file);
-
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
- if(local__fwrite(block->media_catalog_number, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
pack_uint64_(block->lead_in, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
memset(buffer, 0, len);
if(block->is_cd)
buffer[0] |= 0x80;
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
pack_uint32_(block->num_tracks, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
for(i = 0; i < block->num_tracks; i++) {
FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
@@ -1994,32 +2303,32 @@
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
pack_uint64_(track->offset, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
pack_uint32_(track->number, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
- if(local__fwrite(track->isrc, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(track->isrc, 1, len, handle) != len)
+ return false;
FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
memset(buffer, 0, len);
buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
pack_uint32_(track->num_indices, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
for(j = 0; j < track->num_indices; j++) {
FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
@@ -2027,34 +2336,32 @@
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
pack_uint64_(index->offset, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
pack_uint32_(index->number, buffer, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
memset(buffer, 0, len);
- if(local__fwrite(buffer, 1, len, file) != len)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
}
}
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
-FLAC__Metadata_SimpleIteratorStatus write_metadata_block_data_unknown_(FILE *file, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
{
- FLAC__ASSERT(0 != file);
+ if(write_cb(block->data, 1, block_length, handle) != block_length)
+ return false;
- if(local__fwrite(block->data, 1, block_length, file) != block_length)
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
-
- return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
}
FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
@@ -2172,103 +2479,6 @@
return true;
}
-FLAC__bool chain_rewrite_chain_(FLAC__Metadata_Chain *chain)
-{
- FILE *f;
- FLAC__Metadata_Node *node;
- FLAC__Metadata_SimpleIteratorStatus status;
-
- FLAC__ASSERT(0 != chain);
- FLAC__ASSERT(0 != chain->filename);
- FLAC__ASSERT(0 != chain->head);
-
- if(0 == (f = fopen(chain->filename, "r+b"))) {
- chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
- return false;
- }
- if(0 != fseek(f, 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_(f, &status, node->data)) {
- chain->status = get_equivalent_status_(status);
- return false;
- }
- if(!write_metadata_block_data_(f, &status, node->data)) {
- chain->status = get_equivalent_status_(status);
- return false;
- }
- }
-
- /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
-
- (void)fclose(f);
-
- return true;
-}
-
-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;
-}
-
void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
{
FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
@@ -2469,6 +2679,27 @@
return true;
}
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ unsigned n;
+
+ while(bytes > 0) {
+ n = min(sizeof(buffer), bytes);
+ if(read_cb(buffer, 1, n, handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ bytes -= n;
+ }
+
+ return true;
+}
+
FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
{
FLAC__byte buffer[8192];
@@ -2489,6 +2720,26 @@
return true;
}
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(!eof_cb(handle)) {
+ n = read_cb(buffer, 1, sizeof(buffer), handle);
+ if(n == 0 && !eof_cb(handle)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
{
static const char *tempfile_suffix = ".metadata_edit";