📄 metadata_iterators.c
字号:
/* 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 <stdio.h>#include <stdlib.h>#include <string.h>#include "private/metadata.h"#include "FLAC/assert.h"#include "FLAC/file_decoder.h"#ifdef max#undef max#endif#define max(a,b) ((a)>(b)?(a):(b))#ifdef min#undef min#endif#define min(a,b) ((a)<(b)?(a):(b))/**************************************************************************** * * Local function declarations * ***************************************************************************/static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length);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__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 void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);static unsigned seek_to_first_metadata_block_(FILE *f);static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);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);static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);static FLAC__bool get_file_stats_(const char *filename, struct stat *stats);static void set_file_stats_(const char *filename, struct stat *stats);static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);#ifdef FLAC__VALGRIND_TESTINGstatic size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream){ size_t ret = fwrite(ptr, size, nmemb, stream); if(!ferror(stream)) fflush(stream); return ret;}#else#define local__fwrite fwrite#endif/**************************************************************************** * * Level 1 implementation * ***************************************************************************/#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)/* 1 for initial offset, +4 for our own personal use */struct FLAC__Metadata_SimpleIterator { FILE *file; char *filename, *tempfile_path_prefix; FLAC__bool is_writable; FLAC__Metadata_SimpleIteratorStatus status; /*@@@ 2G limits here because of the offset type: */ long offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH]; long first_offset; /* this is the offset to the STREAMINFO block */ unsigned depth; /* this is the metadata block header of the current block we are pointing to: */ FLAC__bool is_last; FLAC__MetadataType type; unsigned length;};FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = { "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR", "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"};FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(){ FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); if(0 != iterator) { iterator->file = 0; iterator->filename = 0; iterator->tempfile_path_prefix = 0; iterator->is_writable = false; iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; iterator->first_offset = iterator->offset[0] = -1; iterator->depth = 0; } return iterator;}static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator){ FLAC__ASSERT(0 != iterator); if(0 != iterator->file) { fclose(iterator->file); iterator->file = 0; } if(0 != iterator->filename) { free(iterator->filename); iterator->filename = 0; } if(0 != iterator->tempfile_path_prefix) { free(iterator->tempfile_path_prefix); iterator->tempfile_path_prefix = 0; }}FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator){ FLAC__ASSERT(0 != iterator); simple_iterator_free_guts_(iterator); free(iterator);}FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator){ FLAC__Metadata_SimpleIteratorStatus status; FLAC__ASSERT(0 != iterator); status = iterator->status; iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; return status;}static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only){ unsigned ret; FLAC__ASSERT(0 != iterator); if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) { iterator->is_writable = false; if(read_only) { if(0 == (iterator->file = fopen(iterator->filename, "rb"))) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; return false; } } else { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; return false; } } else { iterator->is_writable = true; } ret = seek_to_first_metadata_block_(iterator->file); switch(ret) { case 0: iterator->depth = 0; iterator->first_offset = iterator->offset[iterator->depth] = ftell(iterator->file); return read_metadata_block_header_(iterator); case 1: iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; return false; case 2: iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; case 3: iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE; return false; default: FLAC__ASSERT(0); return false; }}#if 0@@@ If we decide to finish implementing this, put this comment back in metadata.h/* * The 'tempfile_path_prefix' allows you to specify a directory where * tempfiles should go. Remember that if your metadata edits cause the * FLAC file to grow, the entire file will have to be rewritten. If * 'tempfile_path_prefix' is NULL, the temp file will be written in the * same directory as the original FLAC file. This makes replacing the * original with the tempfile fast but requires extra space in the same * partition for the tempfile. If space is a problem, you can pass a * directory name belonging to a different partition in * 'tempfile_path_prefix'. Note that you should use the forward slash * '/' as the directory separator. A trailing slash is not needed; it * will be added automatically. */FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);#endifFLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats){ const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */ FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != filename); simple_iterator_free_guts_(iterator); if(0 == (iterator->filename = _strdup(filename))) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; return false; } if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = _strdup(tempfile_path_prefix))) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; return false; } return simple_iterator_prime_input_(iterator, read_only);}FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator){ FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != iterator->file); return iterator->is_writable;}FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator){ FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != iterator->file); if(iterator->is_last) return false; if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } iterator->offset[iterator->depth] = ftell(iterator->file); return read_metadata_block_header_(iterator);}FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator){ long this_offset; FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != iterator->file); if(iterator->offset[iterator->depth] == iterator->first_offset) return false; if(0 != fseek(iterator->file, iterator->first_offset, SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } this_offset = iterator->first_offset; if(!read_metadata_block_header_(iterator)) return false; /* we ignore any error from ftell() and catch it in fseek() */ while(ftell(iterator->file) + (long)iterator->length < iterator->offset[iterator->depth]) { if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } this_offset = ftell(iterator->file); if(!read_metadata_block_header_(iterator)) return false; } iterator->offset[iterator->depth] = this_offset; return true;}FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator){ FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != iterator->file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -