3147 lines · 105.9 KB · C
RawDownload
/* libFLAC - Free Lossless Audio Codec library * Copyright (C) 2001-2009  Josh Coalson * Copyright (C) 2011-2016  Xiph.Org Foundation * * 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 <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h> #include <sys/stat.h> /* for stat(), maybe chmod() */ #include "private/metadata.h" #include "FLAC/stream_decoder.h"#include "share/alloc.h"#include "share/compat.h"#include "share/macros.h"#include "share/safe_str.h"#include "private/macros.h"#include "private/memory.h" // 8bb: hide POSIX warnings#ifdef _MSC_VER#pragma warning(disable: 4996)#endif /* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p /**************************************************************************** * * Local function declarations * ***************************************************************************/ static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes);static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes);static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes);static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t 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, uint32_t *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, uint32_t block_length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t 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, uint32_t max_length);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length);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_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t 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, uint32_t block_length);static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t 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_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t 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, uint32_t 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 uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);static uint32_t 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, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup); static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, 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, FLAC__off_t bytes, 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 flac_stat_s *stats);static void set_file_stats_(const char *filename, struct flac_stat_s *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 0 implementation * ***************************************************************************/ static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); typedef struct {	FLAC__bool got_error;	FLAC__StreamMetadata *object;} level0_client_data; static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type){	level0_client_data cd;	FLAC__StreamDecoder *decoder; 	cd.got_error = false;	cd.object = 0; 	decoder = FLAC__stream_decoder_new(); 	if(0 == decoder)		return 0; 	FLAC__stream_decoder_set_md5_checking(decoder, false);	FLAC__stream_decoder_set_metadata_ignore_all(decoder);	FLAC__stream_decoder_set_metadata_respond(decoder, type); 	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {		(void)FLAC__stream_decoder_finish(decoder);		FLAC__stream_decoder_delete(decoder);		return 0;	} 	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {		(void)FLAC__stream_decoder_finish(decoder);		FLAC__stream_decoder_delete(decoder);		if(0 != cd.object)			FLAC__metadata_object_delete(cd.object);		return 0;	} 	(void)FLAC__stream_decoder_finish(decoder);	FLAC__stream_decoder_delete(decoder); 	return cd.object;} FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo){	FLAC__StreamMetadata *object; 	object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO); 	if (object) {		/* can just copy the contents since STREAMINFO has no internal structure */		*streaminfo = *object;		FLAC__metadata_object_delete(object);		return true;	}	else {		return false;	}} FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags){	*tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT); 	return 0 != *tags;} FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet){	*cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET); 	return 0 != *cuesheet;} FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data){	(void)decoder, (void)frame, (void)buffer, (void)client_data; 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;} void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data){	level0_client_data *cd = (level0_client_data *)client_data;	(void)decoder; 	/*	 * we assume we only get here when the one metadata block we were	 * looking for was passed to us	 */	if(!cd->got_error && 0 == cd->object) {		if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))			cd->got_error = true;	}} void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data){	level0_client_data *cd = (level0_client_data *)client_data;	(void)decoder; 	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)		cd->got_error = true;} FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors){	FLAC__Metadata_SimpleIterator *it;	FLAC__uint64 max_area_seen = 0;	FLAC__uint64 max_depth_seen = 0; 	*picture = 0; 	it = FLAC__metadata_simple_iterator_new();	if(0 == it)		return false;	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {		FLAC__metadata_simple_iterator_delete(it);		return false;	}	do {		if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {			FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);			FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;			/* check constraints */			if(				(type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&				(mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&				(description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&				obj->data.picture.width <= max_width &&				obj->data.picture.height <= max_height &&				obj->data.picture.depth <= max_depth &&				obj->data.picture.colors <= max_colors &&				(area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))			) {				if(*picture)					FLAC__metadata_object_delete(*picture);				*picture = obj;				max_area_seen = area;				max_depth_seen = obj->data.picture.depth;			}			else {				FLAC__metadata_object_delete(obj);			}		}	} while(FLAC__metadata_simple_iterator_next(it)); 	FLAC__metadata_simple_iterator_delete(it); 	return (0 != *picture);}  /**************************************************************************** * * 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;	struct flac_stat_s stats;	FLAC__bool has_stats;	FLAC__bool is_writable;	FLAC__Metadata_SimpleIteratorStatus status;	FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];	FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */	uint32_t depth;	/* this is the metadata block header of the current block we are pointing to: */	FLAC__bool is_last;	FLAC__MetadataType type;	uint32_t 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(void){	FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); 	if(0 != iterator) {		iterator->file = 0;		iterator->filename = 0;		iterator->tempfile_path_prefix = 0;		iterator->has_stats = false;		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){	if(0 != iterator->file) {		fclose(iterator->file);		iterator->file = 0;		if(iterator->has_stats)			set_file_stats_(iterator->filename, &iterator->stats);	}	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){	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; 	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){	uint32_t ret; 	if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) {		iterator->is_writable = false;		if(read_only || errno == EACCES) {			if(0 == (iterator->file = flac_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] = ftello(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:			return false;	}} FLAC_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 'flac_rename(...)' for what it will take to finish implementing this */ 	simple_iterator_free_guts_(iterator); 	if(!read_only && preserve_file_stats)		iterator->has_stats = get_file_stats_(filename, &iterator->stats); 	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){	return iterator->is_writable;} FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator){	if(iterator->is_last)		return false; 	if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;		return false;	} 	iterator->offset[iterator->depth] = ftello(iterator->file); 	return read_metadata_block_header_(iterator);} FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator){	FLAC__off_t this_offset; 	if(iterator->offset[iterator->depth] == iterator->first_offset)		return false; 	if(0 != fseeko(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 ftello() and catch it in fseeko() */	while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) {		if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;			return false;		}

Lines 1–500 of 3147.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t