1/* libFLAC - Free Lossless Audio Codec library
2 * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#if HAVE_CONFIG_H
33#  include <config.h>
34#endif
35
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
42#if defined __BORLANDC__
43#include <utime.h> /* for utime() */
44#else
45#include <sys/utime.h> /* for utime() */
46#endif
47#include <io.h> /* for chmod() */
48#include <sys/types.h> /* for off_t */
49#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
50#define fseeko fseek
51#define ftello ftell
52#endif
53#else
54#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
55#include <utime.h> /* for utime() */
56#include <unistd.h> /* for chown(), unlink() */
57#endif
58#include <sys/stat.h> /* for stat(), maybe chmod() */
59
60#include "private/metadata.h"
61
62#include "FLAC/assert.h"
63#include "FLAC/stream_decoder.h"
64#include "share/alloc.h"
65
66#ifdef max
67#undef max
68#endif
69#define max(a,b) ((a)>(b)?(a):(b))
70#ifdef min
71#undef min
72#endif
73#define min(a,b) ((a)<(b)?(a):(b))
74
75
76/****************************************************************************
77 *
78 * Local function declarations
79 *
80 ***************************************************************************/
81
82static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
83static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
84static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
85static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
86static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
87static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
88
89static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
90static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
91static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length);
92static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
93static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
94static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length);
95static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length);
96static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);
97static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry);
98static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block);
99static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
100static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
101static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);
102static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length);
103
104static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
105static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
106static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
107static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
108static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
109static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
110static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length);
111static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
112static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
113static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
114static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
115static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
116
117static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
118static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
119static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
120
121static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
122static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
123
124static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
125static unsigned seek_to_first_metadata_block_(FILE *f);
126
127static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
128static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, off_t fixup_is_last_flag_offset, FLAC__bool backup);
129
130static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
131static 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, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
132static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
133static 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);
134
135static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
136static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
137static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
138
139static FLAC__bool get_file_stats_(const char *filename, struct stat *stats);
140static void set_file_stats_(const char *filename, struct stat *stats);
141
142static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
143static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
144
145static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
146
147
148#ifdef FLAC__VALGRIND_TESTING
149static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
150{
151	size_t ret = fwrite(ptr, size, nmemb, stream);
152	if(!ferror(stream))
153		fflush(stream);
154	return ret;
155}
156#else
157#define local__fwrite fwrite
158#endif
159
160/****************************************************************************
161 *
162 * Level 0 implementation
163 *
164 ***************************************************************************/
165
166static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
167static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
168static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
169
170typedef struct {
171	FLAC__bool got_error;
172	FLAC__StreamMetadata *object;
173} level0_client_data;
174
175static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
176{
177	level0_client_data cd;
178	FLAC__StreamDecoder *decoder;
179
180	FLAC__ASSERT(0 != filename);
181
182	cd.got_error = false;
183	cd.object = 0;
184
185	decoder = FLAC__stream_decoder_new();
186
187	if(0 == decoder)
188		return 0;
189
190	FLAC__stream_decoder_set_md5_checking(decoder, false);
191	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
192	FLAC__stream_decoder_set_metadata_respond(decoder, type);
193
194	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {
195		(void)FLAC__stream_decoder_finish(decoder);
196		FLAC__stream_decoder_delete(decoder);
197		return 0;
198	}
199
200	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
201		(void)FLAC__stream_decoder_finish(decoder);
202		FLAC__stream_decoder_delete(decoder);
203		if(0 != cd.object)
204			FLAC__metadata_object_delete(cd.object);
205		return 0;
206	}
207
208	(void)FLAC__stream_decoder_finish(decoder);
209	FLAC__stream_decoder_delete(decoder);
210
211	return cd.object;
212}
213
214FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
215{
216	FLAC__StreamMetadata *object;
217
218	FLAC__ASSERT(0 != filename);
219	FLAC__ASSERT(0 != streaminfo);
220
221	object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
222
223	if (object) {
224		/* can just copy the contents since STREAMINFO has no internal structure */
225		*streaminfo = *object;
226		FLAC__metadata_object_delete(object);
227		return true;
228	}
229	else {
230		return false;
231	}
232}
233
234FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
235{
236	FLAC__ASSERT(0 != filename);
237	FLAC__ASSERT(0 != tags);
238
239	*tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
240
241	return 0 != *tags;
242}
243
244FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
245{
246	FLAC__ASSERT(0 != filename);
247	FLAC__ASSERT(0 != cuesheet);
248
249	*cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
250
251	return 0 != *cuesheet;
252}
253
254FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
255{
256	(void)decoder, (void)frame, (void)buffer, (void)client_data;
257
258	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
259}
260
261void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
262{
263	level0_client_data *cd = (level0_client_data *)client_data;
264	(void)decoder;
265
266	/*
267	 * we assume we only get here when the one metadata block we were
268	 * looking for was passed to us
269	 */
270	if(!cd->got_error && 0 == cd->object) {
271		if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
272			cd->got_error = true;
273	}
274}
275
276void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
277{
278	level0_client_data *cd = (level0_client_data *)client_data;
279	(void)decoder;
280
281	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
282		cd->got_error = true;
283}
284
285FLAC_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, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
286{
287	FLAC__Metadata_SimpleIterator *it;
288	FLAC__uint64 max_area_seen = 0;
289	FLAC__uint64 max_depth_seen = 0;
290
291	FLAC__ASSERT(0 != filename);
292	FLAC__ASSERT(0 != picture);
293
294	*picture = 0;
295
296	it = FLAC__metadata_simple_iterator_new();
297	if(0 == it)
298		return false;
299	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
300		FLAC__metadata_simple_iterator_delete(it);
301		return false;
302	}
303	do {
304		if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
305			FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
306			FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
307			/* check constraints */
308			if(
309				(type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
310				(mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
311				(description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
312				obj->data.picture.width <= max_width &&
313				obj->data.picture.height <= max_height &&
314				obj->data.picture.depth <= max_depth &&
315				obj->data.picture.colors <= max_colors &&
316				(area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
317			) {
318				if(*picture)
319					FLAC__metadata_object_delete(*picture);
320				*picture = obj;
321				max_area_seen = area;
322				max_depth_seen = obj->data.picture.depth;
323			}
324			else {
325				FLAC__metadata_object_delete(obj);
326			}
327		}
328	} while(FLAC__metadata_simple_iterator_next(it));
329
330	FLAC__metadata_simple_iterator_delete(it);
331
332	return (0 != *picture);
333}
334
335
336/****************************************************************************
337 *
338 * Level 1 implementation
339 *
340 ***************************************************************************/
341
342#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
343/* 1 for initial offset, +4 for our own personal use */
344
345struct FLAC__Metadata_SimpleIterator {
346	FILE *file;
347	char *filename, *tempfile_path_prefix;
348	struct stat stats;
349	FLAC__bool has_stats;
350	FLAC__bool is_writable;
351	FLAC__Metadata_SimpleIteratorStatus status;
352	off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
353	off_t first_offset; /* this is the offset to the STREAMINFO block */
354	unsigned depth;
355	/* this is the metadata block header of the current block we are pointing to: */
356	FLAC__bool is_last;
357	FLAC__MetadataType type;
358	unsigned length;
359};
360
361FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
362	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
363	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
364	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
365	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
366	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
367	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
368	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
369	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
370	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
371	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
372	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
373	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
374	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
375};
376
377
378FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
379{
380	FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
381
382	if(0 != iterator) {
383		iterator->file = 0;
384		iterator->filename = 0;
385		iterator->tempfile_path_prefix = 0;
386		iterator->has_stats = false;
387		iterator->is_writable = false;
388		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
389		iterator->first_offset = iterator->offset[0] = -1;
390		iterator->depth = 0;
391	}
392
393	return iterator;
394}
395
396static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
397{
398	FLAC__ASSERT(0 != iterator);
399
400	if(0 != iterator->file) {
401		fclose(iterator->file);
402		iterator->file = 0;
403		if(iterator->has_stats)
404			set_file_stats_(iterator->filename, &iterator->stats);
405	}
406	if(0 != iterator->filename) {
407		free(iterator->filename);
408		iterator->filename = 0;
409	}
410	if(0 != iterator->tempfile_path_prefix) {
411		free(iterator->tempfile_path_prefix);
412		iterator->tempfile_path_prefix = 0;
413	}
414}
415
416FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
417{
418	FLAC__ASSERT(0 != iterator);
419
420	simple_iterator_free_guts_(iterator);
421	free(iterator);
422}
423
424FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
425{
426	FLAC__Metadata_SimpleIteratorStatus status;
427
428	FLAC__ASSERT(0 != iterator);
429
430	status = iterator->status;
431	iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
432	return status;
433}
434
435static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
436{
437	unsigned ret;
438
439	FLAC__ASSERT(0 != iterator);
440
441	if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) {
442		iterator->is_writable = false;
443		if(read_only || errno == EACCES) {
444			if(0 == (iterator->file = fopen(iterator->filename, "rb"))) {
445				iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
446				return false;
447			}
448		}
449		else {
450			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
451			return false;
452		}
453	}
454	else {
455		iterator->is_writable = true;
456	}
457
458	ret = seek_to_first_metadata_block_(iterator->file);
459	switch(ret) {
460		case 0:
461			iterator->depth = 0;
462			iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
463			return read_metadata_block_header_(iterator);
464		case 1:
465			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
466			return false;
467		case 2:
468			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
469			return false;
470		case 3:
471			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
472			return false;
473		default:
474			FLAC__ASSERT(0);
475			return false;
476	}
477}
478
479#if 0
480@@@ If we decide to finish implementing this, put this comment back in metadata.h
481/*
482 * The 'tempfile_path_prefix' allows you to specify a directory where
483 * tempfiles should go.  Remember that if your metadata edits cause the
484 * FLAC file to grow, the entire file will have to be rewritten.  If
485 * 'tempfile_path_prefix' is NULL, the temp file will be written in the
486 * same directory as the original FLAC file.  This makes replacing the
487 * original with the tempfile fast but requires extra space in the same
488 * partition for the tempfile.  If space is a problem, you can pass a
489 * directory name belonging to a different partition in
490 * 'tempfile_path_prefix'.  Note that you should use the forward slash
491 * '/' as the directory separator.  A trailing slash is not needed; it
492 * will be added automatically.
493 */
494FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
495#endif
496
497FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
498{
499	const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */
500
501	FLAC__ASSERT(0 != iterator);
502	FLAC__ASSERT(0 != filename);
503
504	simple_iterator_free_guts_(iterator);
505
506	if(!read_only && preserve_file_stats)
507		iterator->has_stats = get_file_stats_(filename, &iterator->stats);
508
509	if(0 == (iterator->filename = strdup(filename))) {
510		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
511		return false;
512	}
513	if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
514		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
515		return false;
516	}
517
518	return simple_iterator_prime_input_(iterator, read_only);
519}
520
521FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
522{
523	FLAC__ASSERT(0 != iterator);
524	FLAC__ASSERT(0 != iterator->file);
525
526	return iterator->is_writable;
527}
528
529FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
530{
531	FLAC__ASSERT(0 != iterator);
532	FLAC__ASSERT(0 != iterator->file);
533
534	if(iterator->is_last)
535		return false;
536
537	if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
538		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
539		return false;
540	}
541
542	iterator->offset[iterator->depth] = ftello(iterator->file);
543
544	return read_metadata_block_header_(iterator);
545}
546
547FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
548{
549	off_t this_offset;
550
551	FLAC__ASSERT(0 != iterator);
552	FLAC__ASSERT(0 != iterator->file);
553
554	if(iterator->offset[iterator->depth] == iterator->first_offset)
555		return false;
556
557	if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
558		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
559		return false;
560	}
561	this_offset = iterator->first_offset;
562	if(!read_metadata_block_header_(iterator))
563		return false;
564
565	/* we ignore any error from ftello() and catch it in fseeko() */
566	while(ftello(iterator->file) + (off_t)iterator->length < iterator->offset[iterator->depth]) {
567		if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
568			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
569			return false;
570		}
571		this_offset = ftello(iterator->file);
572		if(!read_metadata_block_header_(iterator))
573			return false;
574	}
575
576	iterator->offset[iterator->depth] = this_offset;
577
578	return true;
579}
580
581/*@@@@add to tests*/
582FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator)
583{
584	FLAC__ASSERT(0 != iterator);
585	FLAC__ASSERT(0 != iterator->file);
586
587	return iterator->is_last;
588}
589
590/*@@@@add to tests*/
591FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator)
592{
593	FLAC__ASSERT(0 != iterator);
594	FLAC__ASSERT(0 != iterator->file);
595
596	return iterator->offset[iterator->depth];
597}
598
599FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
600{
601	FLAC__ASSERT(0 != iterator);
602	FLAC__ASSERT(0 != iterator->file);
603
604	return iterator->type;
605}
606
607/*@@@@add to tests*/
608FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator)
609{
610	FLAC__ASSERT(0 != iterator);
611	FLAC__ASSERT(0 != iterator->file);
612
613	return iterator->length;
614}
615
616/*@@@@add to tests*/
617FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id)
618{
619	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
620
621	FLAC__ASSERT(0 != iterator);
622	FLAC__ASSERT(0 != iterator->file);
623	FLAC__ASSERT(0 != id);
624
625	if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) {
626		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
627		return false;
628	}
629
630	if(fread(id, 1, id_bytes, iterator->file) != id_bytes) {
631		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
632		return false;
633	}
634
635	/* back up */
636	if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) {
637		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
638		return false;
639	}
640
641	return true;
642}
643
644FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
645{
646	FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
647
648	FLAC__ASSERT(0 != iterator);
649	FLAC__ASSERT(0 != iterator->file);
650
651	if(0 != block) {
652		block->is_last = iterator->is_last;
653		block->length = iterator->length;
654
655		if(!read_metadata_block_data_(iterator, block)) {
656			FLAC__metadata_object_delete(block);
657			return 0;
658		}
659
660		/* back up to the beginning of the block data to stay consistent */
661		if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
662			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
663			FLAC__metadata_object_delete(block);
664			return 0;
665		}
666	}
667	else
668		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
669
670	return block;
671}
672
673FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
674{
675	FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth];)
676	FLAC__bool ret;
677
678	FLAC__ASSERT(0 != iterator);
679	FLAC__ASSERT(0 != iterator->file);
680	FLAC__ASSERT(0 != block);
681
682	if(!iterator->is_writable) {
683		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
684		return false;
685	}
686
687	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
688		if(iterator->type != block->type) {
689			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
690			return false;
691		}
692	}
693
694	block->is_last = iterator->is_last;
695
696	if(iterator->length == block->length)
697		return write_metadata_block_stationary_(iterator, block);
698	else if(iterator->length > block->length) {
699		if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
700			ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
701			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
702			FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
703			return ret;
704		}
705		else {
706			ret = rewrite_whole_file_(iterator, block, /*append=*/false);
707			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
708			FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
709			return ret;
710		}
711	}
712	else /* iterator->length < block->length */ {
713		unsigned padding_leftover = 0;
714		FLAC__bool padding_is_last = false;
715		if(use_padding) {
716			/* first see if we can even use padding */
717			if(iterator->is_last) {
718				use_padding = false;
719			}
720			else {
721				const unsigned extra_padding_bytes_required = block->length - iterator->length;
722				simple_iterator_push_(iterator);
723				if(!FLAC__metadata_simple_iterator_next(iterator)) {
724					(void)simple_iterator_pop_(iterator);
725					return false;
726				}
727				if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
728					use_padding = false;
729				}
730				else {
731					if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
732						padding_leftover = 0;
733						block->is_last = iterator->is_last;
734					}
735					else if(iterator->length < extra_padding_bytes_required)
736						use_padding = false;
737					else {
738						padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
739						padding_is_last = iterator->is_last;
740						block->is_last = false;
741					}
742				}
743				if(!simple_iterator_pop_(iterator))
744					return false;
745			}
746		}
747		if(use_padding) {
748			if(padding_leftover == 0) {
749				ret = write_metadata_block_stationary_(iterator, block);
750				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
751				FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
752				return ret;
753			}
754			else {
755				FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
756				ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
757				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
758				FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
759				return ret;
760			}
761		}
762		else {
763			ret = rewrite_whole_file_(iterator, block, /*append=*/false);
764			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
765			FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
766			return ret;
767		}
768	}
769}
770
771FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
772{
773	unsigned padding_leftover = 0;
774	FLAC__bool padding_is_last = false;
775
776	FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
777	FLAC__bool ret;
778
779	FLAC__ASSERT(0 != iterator);
780	FLAC__ASSERT(0 != iterator->file);
781	FLAC__ASSERT(0 != block);
782
783	if(!iterator->is_writable)
784		return false;
785
786	if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
787		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
788		return false;
789	}
790
791	block->is_last = iterator->is_last;
792
793	if(use_padding) {
794		/* first see if we can even use padding */
795		if(iterator->is_last) {
796			use_padding = false;
797		}
798		else {
799			simple_iterator_push_(iterator);
800			if(!FLAC__metadata_simple_iterator_next(iterator)) {
801				(void)simple_iterator_pop_(iterator);
802				return false;
803			}
804			if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
805				use_padding = false;
806			}
807			else {
808				if(iterator->length == block->length) {
809					padding_leftover = 0;
810					block->is_last = iterator->is_last;
811				}
812				else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
813					use_padding = false;
814				else {
815					padding_leftover = iterator->length - block->length;
816					padding_is_last = iterator->is_last;
817					block->is_last = false;
818				}
819			}
820			if(!simple_iterator_pop_(iterator))
821				return false;
822		}
823	}
824	if(use_padding) {
825		/* move to the next block, which is suitable padding */
826		if(!FLAC__metadata_simple_iterator_next(iterator))
827			return false;
828		if(padding_leftover == 0) {
829			ret = write_metadata_block_stationary_(iterator, block);
830			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
831			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
832			return ret;
833		}
834		else {
835			FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
836			ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
837			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
838			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
839			return ret;
840		}
841	}
842	else {
843		ret = rewrite_whole_file_(iterator, block, /*append=*/true);
844		FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
845		FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
846		return ret;
847	}
848}
849
850FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
851{
852	FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth];)
853	FLAC__bool ret;
854
855	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
856		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
857		return false;
858	}
859
860	if(use_padding) {
861		FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
862		if(0 == padding) {
863			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
864			return false;
865		}
866		padding->length = iterator->length;
867		if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
868			FLAC__metadata_object_delete(padding);
869			return false;
870		}
871		FLAC__metadata_object_delete(padding);
872		if(!FLAC__metadata_simple_iterator_prev(iterator))
873			return false;
874		FLAC__ASSERT(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length == debug_target_offset);
875		FLAC__ASSERT(ftello(iterator->file) + (off_t)iterator->length == debug_target_offset);
876		return true;
877	}
878	else {
879		ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
880		FLAC__ASSERT(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length == debug_target_offset);
881		FLAC__ASSERT(ftello(iterator->file) + (off_t)iterator->length == debug_target_offset);
882		return ret;
883	}
884}
885
886
887
888/****************************************************************************
889 *
890 * Level 2 implementation
891 *
892 ***************************************************************************/
893
894
895typedef struct FLAC__Metadata_Node {
896	FLAC__StreamMetadata *data;
897	struct FLAC__Metadata_Node *prev, *next;
898} FLAC__Metadata_Node;
899
900struct FLAC__Metadata_Chain {
901	char *filename; /* will be NULL if using callbacks */
902	FLAC__bool is_ogg;
903	FLAC__Metadata_Node *head;
904	FLAC__Metadata_Node *tail;
905	unsigned nodes;
906	FLAC__Metadata_ChainStatus status;
907	off_t first_offset, last_offset;
908	/*
909	 * This is the length of the chain initially read from the FLAC file.
910	 * it is used to compare against the current length to decide whether
911	 * or not the whole file has to be rewritten.
912	 */
913	off_t initial_length;
914	/* @@@ hacky, these are currently only needed by ogg reader */
915	FLAC__IOHandle handle;
916	FLAC__IOCallback_Read read_cb;
917};
918
919struct FLAC__Metadata_Iterator {
920	FLAC__Metadata_Chain *chain;
921	FLAC__Metadata_Node *current;
922};
923
924FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
925	"FLAC__METADATA_CHAIN_STATUS_OK",
926	"FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
927	"FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
928	"FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
929	"FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
930	"FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
931	"FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
932	"FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
933	"FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
934	"FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
935	"FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
936	"FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
937	"FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
938	"FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
939	"FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
940	"FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
941};
942
943
944static FLAC__Metadata_Node *node_new_(void)
945{
946	return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node));
947}
948
949static void node_delete_(FLAC__Metadata_Node *node)
950{
951	FLAC__ASSERT(0 != node);
952	if(0 != node->data)
953		FLAC__metadata_object_delete(node->data);
954	free(node);
955}
956
957static void chain_init_(FLAC__Metadata_Chain *chain)
958{
959	FLAC__ASSERT(0 != chain);
960
961	chain->filename = 0;
962	chain->is_ogg = false;
963	chain->head = chain->tail = 0;
964	chain->nodes = 0;
965	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
966	chain->initial_length = 0;
967	chain->read_cb = 0;
968}
969
970static void chain_clear_(FLAC__Metadata_Chain *chain)
971{
972	FLAC__Metadata_Node *node, *next;
973
974	FLAC__ASSERT(0 != chain);
975
976	for(node = chain->head; node; ) {
977		next = node->next;
978		node_delete_(node);
979		node = next;
980	}
981
982	if(0 != chain->filename)
983		free(chain->filename);
984
985	chain_init_(chain);
986}
987
988static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
989{
990	FLAC__ASSERT(0 != chain);
991	FLAC__ASSERT(0 != node);
992	FLAC__ASSERT(0 != node->data);
993
994	node->next = node->prev = 0;
995	node->data->is_last = true;
996	if(0 != chain->tail)
997		chain->tail->data->is_last = false;
998
999	if(0 == chain->head)
1000		chain->head = node;
1001	else {
1002		FLAC__ASSERT(0 != chain->tail);
1003		chain->tail->next = node;
1004		node->prev = chain->tail;
1005	}
1006	chain->tail = node;
1007	chain->nodes++;
1008}
1009
1010static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
1011{
1012	FLAC__ASSERT(0 != chain);
1013	FLAC__ASSERT(0 != node);
1014
1015	if(node == chain->head)
1016		chain->head = node->next;
1017	else
1018		node->prev->next = node->next;
1019
1020	if(node == chain->tail)
1021		chain->tail = node->prev;
1022	else
1023		node->next->prev = node->prev;
1024
1025	if(0 != chain->tail)
1026		chain->tail->data->is_last = true;
1027
1028	chain->nodes--;
1029}
1030
1031static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
1032{
1033	chain_remove_node_(chain, node);
1034	node_delete_(node);
1035}
1036
1037static off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
1038{
1039	const FLAC__Metadata_Node *node;
1040	off_t length = 0;
1041	for(node = chain->head; node; node = node->next)
1042		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
1043	return length;
1044}
1045
1046static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
1047{
1048	FLAC__ASSERT(0 != node);
1049	FLAC__ASSERT(0 != node->data);
1050	FLAC__ASSERT(0 != iterator);
1051	FLAC__ASSERT(0 != iterator->current);
1052	FLAC__ASSERT(0 != iterator->chain);
1053	FLAC__ASSERT(0 != iterator->chain->head);
1054	FLAC__ASSERT(0 != iterator->chain->tail);
1055
1056	node->data->is_last = false;
1057
1058	node->prev = iterator->current->prev;
1059	node->next = iterator->current;
1060
1061	if(0 == node->prev)
1062		iterator->chain->head = node;
1063	else
1064		node->prev->next = node;
1065
1066	iterator->current->prev = node;
1067
1068	iterator->chain->nodes++;
1069}
1070
1071static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
1072{
1073	FLAC__ASSERT(0 != node);
1074	FLAC__ASSERT(0 != node->data);
1075	FLAC__ASSERT(0 != iterator);
1076	FLAC__ASSERT(0 != iterator->current);
1077	FLAC__ASSERT(0 != iterator->chain);
1078	FLAC__ASSERT(0 != iterator->chain->head);
1079	FLAC__ASSERT(0 != iterator->chain->tail);
1080
1081	iterator->current->data->is_last = false;
1082
1083	node->prev = iterator->current;
1084	node->next = iterator->current->next;
1085
1086	if(0 == node->next)
1087		iterator->chain->tail = node;
1088	else
1089		node->next->prev = node;
1090
1091	node->prev->next = node;
1092
1093	iterator->chain->tail->data->is_last = true;
1094
1095	iterator->chain->nodes++;
1096}
1097
1098/* return true iff node and node->next are both padding */
1099static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
1100{
1101	if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
1102		const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
1103		node->data->length += growth;
1104
1105		chain_delete_node_(chain, node->next);
1106		return true;
1107	}
1108	else
1109		return false;
1110}
1111
1112/* Returns the new length of the chain, or 0 if there was an error. */
1113/* WATCHOUT: This can get called multiple times before a write, so
1114 * it should still work when this happens.
1115 */
1116/* WATCHOUT: Make sure to also update the logic in
1117 * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
1118 */
1119static off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
1120{
1121	off_t current_length = chain_calculate_length_(chain);
1122
1123	if(use_padding) {
1124		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
1125		if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
1126			const off_t delta = chain->initial_length - current_length;
1127			chain->tail->data->length += delta;
1128			current_length += delta;
1129			FLAC__ASSERT(current_length == chain->initial_length);
1130		}
1131		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
1132		else if(current_length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
1133			FLAC__StreamMetadata *padding;
1134			FLAC__Metadata_Node *node;
1135			if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
1136				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1137				return 0;
1138			}
1139			padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
1140			if(0 == (node = node_new_())) {
1141				FLAC__metadata_object_delete(padding);
1142				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1143				return 0;
1144			}
1145			node->data = padding;
1146			chain_append_node_(chain, node);
1147			current_length = chain_calculate_length_(chain);
1148			FLAC__ASSERT(current_length == chain->initial_length);
1149		}
1150		/* 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 */
1151		else if(current_length > chain->initial_length) {
1152			const off_t delta = current_length - chain->initial_length;
1153			if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
1154				/* if the delta is exactly the size of the last padding block, remove the padding block */
1155				if((off_t)chain->tail->data->length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
1156					chain_delete_node_(chain, chain->tail);
1157					current_length = chain_calculate_length_(chain);
1158					FLAC__ASSERT(current_length == chain->initial_length);
1159				}
1160				/* if there is at least 'delta' bytes of padding, trim the padding down */
1161				else if((off_t)chain->tail->data->length >= delta) {
1162					chain->tail->data->length -= delta;
1163					current_length -= delta;
1164					FLAC__ASSERT(current_length == chain->initial_length);
1165				}
1166			}
1167		}
1168	}
1169
1170	return current_length;
1171}
1172
1173static 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)
1174{
1175	FLAC__Metadata_Node *node;
1176
1177	FLAC__ASSERT(0 != chain);
1178
1179	/* we assume we're already at the beginning of the file */
1180
1181	switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
1182		case 0:
1183			break;
1184		case 1:
1185			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1186			return false;
1187		case 2:
1188			chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1189			return false;
1190		case 3:
1191			chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
1192			return false;
1193		default:
1194			FLAC__ASSERT(0);
1195			return false;
1196	}
1197
1198	{
1199		FLAC__int64 pos = tell_cb(handle);
1200		if(pos < 0) {
1201			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1202			return false;
1203		}
1204		chain->first_offset = (off_t)pos;
1205	}
1206
1207	{
1208		FLAC__bool is_last;
1209		FLAC__MetadataType type;
1210		unsigned length;
1211
1212		do {
1213			node = node_new_();
1214			if(0 == node) {
1215				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1216				return false;
1217			}
1218
1219			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
1220				node_delete_(node);
1221				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1222				return false;
1223			}
1224
1225			node->data = FLAC__metadata_object_new(type);
1226			if(0 == node->data) {
1227				node_delete_(node);
1228				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1229				return false;
1230			}
1231
1232			node->data->is_last = is_last;
1233			node->data->length = length;
1234
1235			chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
1236			if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
1237				node_delete_(node);
1238				return false;
1239			}
1240			chain_append_node_(chain, node);
1241		} while(!is_last);
1242	}
1243
1244	{
1245		FLAC__int64 pos = tell_cb(handle);
1246		if(pos < 0) {
1247			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
1248			return false;
1249		}
1250		chain->last_offset = (off_t)pos;
1251	}
1252
1253	chain->initial_length = chain_calculate_length_(chain);
1254
1255	return true;
1256}
1257
1258static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
1259{
1260	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
1261	(void)decoder;
1262	if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
1263		*bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle);
1264		if(*bytes == 0)
1265			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
1266		else
1267			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
1268	}
1269	else
1270		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
1271}
1272
1273static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
1274{
1275	(void)decoder, (void)frame, (void)buffer, (void)client_data;
1276	return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
1277}
1278
1279static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
1280{
1281	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
1282	FLAC__Metadata_Node *node;
1283
1284	(void)decoder;
1285
1286	node = node_new_();
1287	if(0 == node) {
1288		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1289		return;
1290	}
1291
1292	node->data = FLAC__metadata_object_clone(metadata);
1293	if(0 == node->data) {
1294		node_delete_(node);
1295		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1296		return;
1297	}
1298
1299	chain_append_node_(chain, node);
1300}
1301
1302static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
1303{
1304	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
1305	(void)decoder, (void)status;
1306	chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
1307}
1308
1309static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
1310{
1311	FLAC__StreamDecoder *decoder;
1312
1313	FLAC__ASSERT(0 != chain);
1314
1315	/* we assume we're already at the beginning of the file */
1316
1317	chain->handle = handle;
1318	chain->read_cb = read_cb;
1319	if(0 == (decoder = FLAC__stream_decoder_new())) {
1320		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1321		return false;
1322	}
1323	FLAC__stream_decoder_set_metadata_respond_all(decoder);
1324	if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
1325		FLAC__stream_decoder_delete(decoder);
1326		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
1327		return false;
1328	}
1329
1330	chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
1331
1332	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
1333		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
1334	if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
1335		FLAC__stream_decoder_delete(decoder);
1336		return false;
1337	}
1338
1339	FLAC__stream_decoder_delete(decoder);
1340
1341	chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
1342
1343	chain->initial_length = chain_calculate_length_(chain);
1344
1345	return true;
1346}
1347
1348static 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)
1349{
1350	FLAC__Metadata_Node *node;
1351
1352	FLAC__ASSERT(0 != chain);
1353	FLAC__ASSERT(0 != chain->head);
1354
1355	if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
1356		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1357		return false;
1358	}
1359
1360	for(node = chain->head; node; node = node->next) {
1361		if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
1362			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1363			return false;
1364		}
1365		if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
1366			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1367			return false;
1368		}
1369	}
1370
1371	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
1372
1373	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
1374	return true;
1375}
1376
1377static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
1378{
1379	FILE *file;
1380	FLAC__bool ret;
1381
1382	FLAC__ASSERT(0 != chain->filename);
1383
1384	if(0 == (file = fopen(chain->filename, "r+b"))) {
1385		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
1386		return false;
1387	}
1388
1389	/* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
1390	ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
1391
1392	fclose(file);
1393
1394	return ret;
1395}
1396
1397static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
1398{
1399	FILE *f, *tempfile;
1400	char *tempfilename;
1401	FLAC__Metadata_SimpleIteratorStatus status;
1402	const FLAC__Metadata_Node *node;
1403
1404	FLAC__ASSERT(0 != chain);
1405	FLAC__ASSERT(0 != chain->filename);
1406	FLAC__ASSERT(0 != chain->head);
1407
1408	/* copy the file prefix (data up to first metadata block */
1409	if(0 == (f = fopen(chain->filename, "rb"))) {
1410		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
1411		return false;
1412	}
1413	if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
1414		chain->status = get_equivalent_status_(status);
1415		cleanup_tempfile_(&tempfile, &tempfilename);
1416		return false;
1417	}
1418	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
1419		chain->status = get_equivalent_status_(status);
1420		cleanup_tempfile_(&tempfile, &tempfilename);
1421		return false;
1422	}
1423
1424	/* write the metadata */
1425	for(node = chain->head; node; node = node->next) {
1426		if(!write_metadata_block_header_(tempfile, &status, node->data)) {
1427			chain->status = get_equivalent_status_(status);
1428			return false;
1429		}
1430		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
1431			chain->status = get_equivalent_status_(status);
1432			return false;
1433		}
1434	}
1435	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
1436
1437	/* copy the file postfix (everything after the metadata) */
1438	if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
1439		cleanup_tempfile_(&tempfile, &tempfilename);
1440		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1441		return false;
1442	}
1443	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
1444		cleanup_tempfile_(&tempfile, &tempfilename);
1445		chain->status = get_equivalent_status_(status);
1446		return false;
1447	}
1448
1449	/* move the tempfile on top of the original */
1450	(void)fclose(f);
1451	if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
1452		return false;
1453
1454	return true;
1455}
1456
1457/* assumes 'handle' is already at beginning of file */
1458static 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)
1459{
1460	FLAC__Metadata_SimpleIteratorStatus status;
1461	const FLAC__Metadata_Node *node;
1462
1463	FLAC__ASSERT(0 != chain);
1464	FLAC__ASSERT(0 == chain->filename);
1465	FLAC__ASSERT(0 != chain->head);
1466
1467	/* copy the file prefix (data up to first metadata block */
1468	if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
1469		chain->status = get_equivalent_status_(status);
1470		return false;
1471	}
1472
1473	/* write the metadata */
1474	for(node = chain->head; node; node = node->next) {
1475		if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
1476			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1477			return false;
1478		}
1479		if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
1480			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
1481			return false;
1482		}
1483	}
1484	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
1485
1486	/* copy the file postfix (everything after the metadata) */
1487	if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
1488		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1489		return false;
1490	}
1491	if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
1492		chain->status = get_equivalent_status_(status);
1493		return false;
1494	}
1495
1496	return true;
1497}
1498
1499FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
1500{
1501	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
1502
1503	if(0 != chain)
1504		chain_init_(chain);
1505
1506	return chain;
1507}
1508
1509FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
1510{
1511	FLAC__ASSERT(0 != chain);
1512
1513	chain_clear_(chain);
1514
1515	free(chain);
1516}
1517
1518FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
1519{
1520	FLAC__Metadata_ChainStatus status;
1521
1522	FLAC__ASSERT(0 != chain);
1523
1524	status = chain->status;
1525	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
1526	return status;
1527}
1528
1529static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
1530{
1531	FILE *file;
1532	FLAC__bool ret;
1533
1534	FLAC__ASSERT(0 != chain);
1535	FLAC__ASSERT(0 != filename);
1536
1537	chain_clear_(chain);
1538
1539	if(0 == (chain->filename = strdup(filename))) {
1540		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
1541		return false;
1542	}
1543
1544	chain->is_ogg = is_ogg;
1545
1546	if(0 == (file = fopen(filename, "rb"))) {
1547		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
1548		return false;
1549	}
1550
1551	/* the function also sets chain->status for us */
1552	ret = is_ogg?
1553		chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
1554		chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_)
1555	;
1556
1557	fclose(file);
1558
1559	return ret;
1560}
1561
1562FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
1563{
1564	return chain_read_(chain, filename, /*is_ogg=*/false);
1565}
1566
1567/*@@@@add to tests*/
1568FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename)
1569{
1570	return chain_read_(chain, filename, /*is_ogg=*/true);
1571}
1572
1573static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
1574{
1575	FLAC__bool ret;
1576
1577	FLAC__ASSERT(0 != chain);
1578
1579	chain_clear_(chain);
1580
1581	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
1582		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1583		return false;
1584	}
1585
1586	chain->is_ogg = is_ogg;
1587
1588	/* rewind */
1589	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
1590		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1591		return false;
1592	}
1593
1594	/* the function also sets chain->status for us */
1595	ret = is_ogg?
1596		chain_read_ogg_cb_(chain, handle, callbacks.read) :
1597		chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)
1598	;
1599
1600	return ret;
1601}
1602
1603FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
1604{
1605	return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false);
1606}
1607
1608/*@@@@add to tests*/
1609FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
1610{
1611	return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true);
1612}
1613
1614FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
1615{
1616	/* This does all the same checks that are in chain_prepare_for_write_()
1617	 * but doesn't actually alter the chain.  Make sure to update the logic
1618	 * here if chain_prepare_for_write_() changes.
1619	 */
1620	const off_t current_length = chain_calculate_length_(chain);
1621
1622	FLAC__ASSERT(0 != chain);
1623
1624	if(use_padding) {
1625		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
1626		if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING)
1627			return false;
1628		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
1629		else if(current_length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length)
1630			return false;
1631		/* 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 */
1632		else if(current_length > chain->initial_length) {
1633			const off_t delta = current_length - chain->initial_length;
1634			if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
1635				/* if the delta is exactly the size of the last padding block, remove the padding block */
1636				if((off_t)chain->tail->data->length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta)
1637					return false;
1638				/* if there is at least 'delta' bytes of padding, trim the padding down */
1639				else if((off_t)chain->tail->data->length >= delta)
1640					return false;
1641			}
1642		}
1643	}
1644
1645	return (current_length != chain->initial_length);
1646}
1647
1648FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
1649{
1650	struct stat stats;
1651	const char *tempfile_path_prefix = 0;
1652	off_t current_length;
1653
1654	FLAC__ASSERT(0 != chain);
1655
1656	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
1657		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
1658		return false;
1659	}
1660
1661	if (0 == chain->filename) {
1662		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
1663		return false;
1664	}
1665
1666	current_length = chain_prepare_for_write_(chain, use_padding);
1667
1668	/* a return value of 0 means there was an error; chain->status is already set */
1669	if (0 == current_length)
1670		return false;
1671
1672	if(preserve_file_stats)
1673		get_file_stats_(chain->filename, &stats);
1674
1675	if(current_length == chain->initial_length) {
1676		if(!chain_rewrite_metadata_in_place_(chain))
1677			return false;
1678	}
1679	else {
1680		if(!chain_rewrite_file_(chain, tempfile_path_prefix))
1681			return false;
1682
1683		/* recompute lengths and offsets */
1684		{
1685			const FLAC__Metadata_Node *node;
1686			chain->initial_length = current_length;
1687			chain->last_offset = chain->first_offset;
1688			for(node = chain->head; node; node = node->next)
1689				chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
1690		}
1691	}
1692
1693	if(preserve_file_stats)
1694		set_file_stats_(chain->filename, &stats);
1695
1696	return true;
1697}
1698
1699FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
1700{
1701	off_t current_length;
1702
1703	FLAC__ASSERT(0 != chain);
1704
1705	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
1706		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
1707		return false;
1708	}
1709
1710	if (0 != chain->filename) {
1711		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
1712		return false;
1713	}
1714
1715	if (0 == callbacks.write || 0 == callbacks.seek) {
1716		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1717		return false;
1718	}
1719
1720	if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
1721		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
1722		return false;
1723	}
1724
1725	current_length = chain_prepare_for_write_(chain, use_padding);
1726
1727	/* a return value of 0 means there was an error; chain->status is already set */
1728	if (0 == current_length)
1729		return false;
1730
1731	FLAC__ASSERT(current_length == chain->initial_length);
1732
1733	return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
1734}
1735
1736FLAC_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)
1737{
1738	off_t current_length;
1739
1740	FLAC__ASSERT(0 != chain);
1741
1742	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
1743		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
1744		return false;
1745	}
1746
1747	if (0 != chain->filename) {
1748		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
1749		return false;
1750	}
1751
1752	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
1753		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1754		return false;
1755	}
1756	if (0 == temp_callbacks.write) {
1757		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
1758		return false;
1759	}
1760
1761	if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
1762		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
1763		return false;
1764	}
1765
1766	current_length = chain_prepare_for_write_(chain, use_padding);
1767
1768	/* a return value of 0 means there was an error; chain->status is already set */
1769	if (0 == current_length)
1770		return false;
1771
1772	FLAC__ASSERT(current_length != chain->initial_length);
1773
1774	/* rewind */
1775	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
1776		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
1777		return false;
1778	}
1779
1780	if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
1781		return false;
1782
1783	/* recompute lengths and offsets */
1784	{
1785		const FLAC__Metadata_Node *node;
1786		chain->initial_length = current_length;
1787		chain->last_offset = chain->first_offset;
1788		for(node = chain->head; node; node = node->next)
1789			chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
1790	}
1791
1792	return true;
1793}
1794
1795FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
1796{
1797	FLAC__Metadata_Node *node;
1798
1799	FLAC__ASSERT(0 != chain);
1800
1801	for(node = chain->head; node; ) {
1802		if(!chain_merge_adjacent_padding_(chain, node))
1803			node = node->next;
1804	}
1805}
1806
1807FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
1808{
1809	FLAC__Metadata_Node *node, *save;
1810	unsigned i;
1811
1812	FLAC__ASSERT(0 != chain);
1813
1814	/*
1815	 * Don't try and be too smart... this simple algo is good enough for
1816	 * the small number of nodes that we deal with.
1817	 */
1818	for(i = 0, node = chain->head; i < chain->nodes; i++) {
1819		if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
1820			save = node->next;
1821			chain_remove_node_(chain, node);
1822			chain_append_node_(chain, node);
1823			node = save;
1824		}
1825		else {
1826			node = node->next;
1827		}
1828	}
1829
1830	FLAC__metadata_chain_merge_padding(chain);
1831}
1832
1833
1834FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
1835{
1836	FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
1837
1838	/* calloc() implies:
1839		iterator->current = 0;
1840		iterator->chain = 0;
1841	*/
1842
1843	return iterator;
1844}
1845
1846FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
1847{
1848	FLAC__ASSERT(0 != iterator);
1849
1850	free(iterator);
1851}
1852
1853FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
1854{
1855	FLAC__ASSERT(0 != iterator);
1856	FLAC__ASSERT(0 != chain);
1857	FLAC__ASSERT(0 != chain->head);
1858
1859	iterator->chain = chain;
1860	iterator->current = chain->head;
1861}
1862
1863FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
1864{
1865	FLAC__ASSERT(0 != iterator);
1866
1867	if(0 == iterator->current || 0 == iterator->current->next)
1868		return false;
1869
1870	iterator->current = iterator->current->next;
1871	return true;
1872}
1873
1874FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
1875{
1876	FLAC__ASSERT(0 != iterator);
1877
1878	if(0 == iterator->current || 0 == iterator->current->prev)
1879		return false;
1880
1881	iterator->current = iterator->current->prev;
1882	return true;
1883}
1884
1885FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
1886{
1887	FLAC__ASSERT(0 != iterator);
1888	FLAC__ASSERT(0 != iterator->current);
1889	FLAC__ASSERT(0 != iterator->current->data);
1890
1891	return iterator->current->data->type;
1892}
1893
1894FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
1895{
1896	FLAC__ASSERT(0 != iterator);
1897	FLAC__ASSERT(0 != iterator->current);
1898
1899	return iterator->current->data;
1900}
1901
1902FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
1903{
1904	FLAC__ASSERT(0 != iterator);
1905	FLAC__ASSERT(0 != block);
1906	return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
1907}
1908
1909FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
1910{
1911	FLAC__Metadata_Node *save;
1912
1913	FLAC__ASSERT(0 != iterator);
1914	FLAC__ASSERT(0 != iterator->current);
1915
1916	if(0 == iterator->current->prev) {
1917		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
1918		return false;
1919	}
1920
1921	save = iterator->current->prev;
1922
1923	if(replace_with_padding) {
1924		FLAC__metadata_object_delete_data(iterator->current->data);
1925		iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
1926	}
1927	else {
1928		chain_delete_node_(iterator->chain, iterator->current);
1929	}
1930
1931	iterator->current = save;
1932	return true;
1933}
1934
1935FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
1936{
1937	FLAC__Metadata_Node *node;
1938
1939	FLAC__ASSERT(0 != iterator);
1940	FLAC__ASSERT(0 != iterator->current);
1941	FLAC__ASSERT(0 != block);
1942
1943	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
1944		return false;
1945
1946	if(0 == iterator->current->prev) {
1947		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
1948		return false;
1949	}
1950
1951	if(0 == (node = node_new_()))
1952		return false;
1953
1954	node->data = block;
1955	iterator_insert_node_(iterator, node);
1956	iterator->current = node;
1957	return true;
1958}
1959
1960FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
1961{
1962	FLAC__Metadata_Node *node;
1963
1964	FLAC__ASSERT(0 != iterator);
1965	FLAC__ASSERT(0 != iterator->current);
1966	FLAC__ASSERT(0 != block);
1967
1968	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
1969		return false;
1970
1971	if(0 == (node = node_new_()))
1972		return false;
1973
1974	node->data = block;
1975	iterator_insert_node_after_(iterator, node);
1976	iterator->current = node;
1977	return true;
1978}
1979
1980
1981/****************************************************************************
1982 *
1983 * Local function definitions
1984 *
1985 ***************************************************************************/
1986
1987void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
1988{
1989	unsigned i;
1990
1991	b += bytes;
1992
1993	for(i = 0; i < bytes; i++) {
1994		*(--b) = (FLAC__byte)(val & 0xff);
1995		val >>= 8;
1996	}
1997}
1998
1999void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
2000{
2001	unsigned i;
2002
2003	for(i = 0; i < bytes; i++) {
2004		*(b++) = (FLAC__byte)(val & 0xff);
2005		val >>= 8;
2006	}
2007}
2008
2009void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
2010{
2011	unsigned i;
2012
2013	b += bytes;
2014
2015	for(i = 0; i < bytes; i++) {
2016		*(--b) = (FLAC__byte)(val & 0xff);
2017		val >>= 8;
2018	}
2019}
2020
2021FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
2022{
2023	FLAC__uint32 ret = 0;
2024	unsigned i;
2025
2026	for(i = 0; i < bytes; i++)
2027		ret = (ret << 8) | (FLAC__uint32)(*b++);
2028
2029	return ret;
2030}
2031
2032FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
2033{
2034	FLAC__uint32 ret = 0;
2035	unsigned i;
2036
2037	b += bytes;
2038
2039	for(i = 0; i < bytes; i++)
2040		ret = (ret << 8) | (FLAC__uint32)(*--b);
2041
2042	return ret;
2043}
2044
2045FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
2046{
2047	FLAC__uint64 ret = 0;
2048	unsigned i;
2049
2050	for(i = 0; i < bytes; i++)
2051		ret = (ret << 8) | (FLAC__uint64)(*b++);
2052
2053	return ret;
2054}
2055
2056FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
2057{
2058	FLAC__ASSERT(0 != iterator);
2059	FLAC__ASSERT(0 != iterator->file);
2060
2061	if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
2062		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2063		return false;
2064	}
2065
2066	return true;
2067}
2068
2069FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
2070{
2071	FLAC__ASSERT(0 != iterator);
2072	FLAC__ASSERT(0 != iterator->file);
2073
2074	iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
2075
2076	return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
2077}
2078
2079FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length)
2080{
2081	FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
2082
2083	if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
2084		return false;
2085
2086	*is_last = raw_header[0] & 0x80? true : false;
2087	*type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
2088	*length = unpack_uint32_(raw_header + 1, 3);
2089
2090	/* Note that we don't check:
2091	 *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
2092	 * we just will read in an opaque block
2093	 */
2094
2095	return true;
2096}
2097
2098FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
2099{
2100	switch(block->type) {
2101		case FLAC__METADATA_TYPE_STREAMINFO:
2102			return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
2103		case FLAC__METADATA_TYPE_PADDING:
2104			return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
2105		case FLAC__METADATA_TYPE_APPLICATION:
2106			return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
2107		case FLAC__METADATA_TYPE_SEEKTABLE:
2108			return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
2109		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
2110			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment);
2111		case FLAC__METADATA_TYPE_CUESHEET:
2112			return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
2113		case FLAC__METADATA_TYPE_PICTURE:
2114			return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
2115		default:
2116			return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
2117	}
2118}
2119
2120FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
2121{
2122	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
2123
2124	if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
2125		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2126
2127	b = buffer;
2128
2129	/* we are using hardcoded numbers for simplicity but we should
2130	 * probably eventually write a bit-level unpacker and use the
2131	 * _STREAMINFO_ constants.
2132	 */
2133	block->min_blocksize = unpack_uint32_(b, 2); b += 2;
2134	block->max_blocksize = unpack_uint32_(b, 2); b += 2;
2135	block->min_framesize = unpack_uint32_(b, 3); b += 3;
2136	block->max_framesize = unpack_uint32_(b, 3); b += 3;
2137	block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
2138	block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
2139	block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
2140	block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
2141	memcpy(block->md5sum, b+8, 16);
2142
2143	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2144}
2145
2146FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length)
2147{
2148	(void)block; /* nothing to do; we don't care about reading the padding bytes */
2149
2150	if(0 != seek_cb(handle, block_length, SEEK_CUR))
2151		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2152
2153	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2154}
2155
2156FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length)
2157{
2158	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
2159
2160	if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
2161		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2162
2163	if(block_length < id_bytes)
2164		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2165
2166	block_length -= id_bytes;
2167
2168	if(block_length == 0) {
2169		block->data = 0;
2170	}
2171	else {
2172		if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
2173			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2174
2175		if(read_cb(block->data, 1, block_length, handle) != block_length)
2176			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2177	}
2178
2179	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2180}
2181
2182FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
2183{
2184	unsigned i;
2185	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
2186
2187	FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
2188
2189	block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
2190
2191	if(block->num_points == 0)
2192		block->points = 0;
2193	else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)safe_malloc_mul_2op_(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint))))
2194		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2195
2196	for(i = 0; i < block->num_points; i++) {
2197		if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
2198			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2199		/* some MAGIC NUMBERs here */
2200		block->points[i].sample_number = unpack_uint64_(buffer, 8);
2201		block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
2202		block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
2203	}
2204
2205	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2206}
2207
2208FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry)
2209{
2210	const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
2211	FLAC__byte buffer[4]; /* magic number is asserted below */
2212
2213	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer));
2214
2215	if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
2216		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2217	entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
2218
2219	if(0 != entry->entry)
2220		free(entry->entry);
2221
2222	if(entry->length == 0) {
2223		entry->entry = 0;
2224	}
2225	else {
2226		if(0 == (entry->entry = (FLAC__byte*)safe_malloc_add_2op_(entry->length, /*+*/1)))
2227			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2228
2229		if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
2230			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2231
2232		entry->entry[entry->length] = '\0';
2233	}
2234
2235	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2236}
2237
2238FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block)
2239{
2240	unsigned i;
2241	FLAC__Metadata_SimpleIteratorStatus status;
2242	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
2243	FLAC__byte buffer[4]; /* magic number is asserted below */
2244
2245	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer));
2246
2247	if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string))))
2248		return status;
2249
2250	if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
2251		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2252	block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
2253
2254	if(block->num_comments == 0) {
2255		block->comments = 0;
2256	}
2257	else if(0 == (block->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry))))
2258		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2259
2260	for(i = 0; i < block->num_comments; i++) {
2261		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i)))
2262			return status;
2263	}
2264
2265	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2266}
2267
2268FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
2269{
2270	unsigned i, len;
2271	FLAC__byte buffer[32]; /* asserted below that this is big enough */
2272
2273	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
2274	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
2275	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
2276
2277	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
2278	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
2279	if(read_cb(buffer, 1, len, handle) != len)
2280		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2281	track->offset = unpack_uint64_(buffer, len);
2282
2283	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
2284	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
2285	if(read_cb(buffer, 1, len, handle) != len)
2286		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2287	track->number = (FLAC__byte)unpack_uint32_(buffer, len);
2288
2289	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
2290	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
2291	if(read_cb(track->isrc, 1, len, handle) != len)
2292		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2293
2294	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);
2295	len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
2296	if(read_cb(buffer, 1, len, handle) != len)
2297		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2298	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
2299	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
2300	track->type = buffer[0] >> 7;
2301	track->pre_emphasis = (buffer[0] >> 6) & 1;
2302
2303	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
2304	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
2305	if(read_cb(buffer, 1, len, handle) != len)
2306		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2307	track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
2308
2309	if(track->num_indices == 0) {
2310		track->indices = 0;
2311	}
2312	else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
2313		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2314
2315	for(i = 0; i < track->num_indices; i++) {
2316		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
2317		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
2318		if(read_cb(buffer, 1, len, handle) != len)
2319			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2320		track->indices[i].offset = unpack_uint64_(buffer, len);
2321
2322		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
2323		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
2324		if(read_cb(buffer, 1, len, handle) != len)
2325			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2326		track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
2327
2328		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
2329		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
2330		if(read_cb(buffer, 1, len, handle) != len)
2331			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2332	}
2333
2334	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2335}
2336
2337FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
2338{
2339	unsigned i, len;
2340	FLAC__Metadata_SimpleIteratorStatus status;
2341	FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
2342
2343	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
2344	FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
2345
2346	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
2347	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
2348	if(read_cb(block->media_catalog_number, 1, len, handle) != len)
2349		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2350
2351	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
2352	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
2353	if(read_cb(buffer, 1, len, handle) != len)
2354		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2355	block->lead_in = unpack_uint64_(buffer, len);
2356
2357	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
2358	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
2359	if(read_cb(buffer, 1, len, handle) != len)
2360		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2361	block->is_cd = buffer[0]&0x80? true : false;
2362
2363	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
2364	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
2365	if(read_cb(buffer, 1, len, handle) != len)
2366		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2367	block->num_tracks = unpack_uint32_(buffer, len);
2368
2369	if(block->num_tracks == 0) {
2370		block->tracks = 0;
2371	}
2372	else if(0 == (block->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
2373		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2374
2375	for(i = 0; i < block->num_tracks; i++) {
2376		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
2377			return status;
2378	}
2379
2380	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2381}
2382
2383static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
2384{
2385	FLAC__byte buffer[sizeof(FLAC__uint32)];
2386
2387	FLAC__ASSERT(0 != data);
2388	FLAC__ASSERT(length_len%8 == 0);
2389
2390	length_len /= 8; /* convert to bytes */
2391
2392	FLAC__ASSERT(sizeof(buffer) >= length_len);
2393
2394	if(read_cb(buffer, 1, length_len, handle) != length_len)
2395		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2396	*length = unpack_uint32_(buffer, length_len);
2397
2398	if(0 != *data)
2399		free(*data);
2400
2401	if(0 == (*data = (FLAC__byte*)safe_malloc_add_2op_(*length, /*+*/1)))
2402		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2403
2404	if(*length > 0) {
2405		if(read_cb(*data, 1, *length, handle) != *length)
2406			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2407	}
2408
2409	(*data)[*length] = '\0';
2410
2411	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2412}
2413
2414FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
2415{
2416	FLAC__Metadata_SimpleIteratorStatus status;
2417	FLAC__byte buffer[4]; /* asserted below that this is big enough */
2418	FLAC__uint32 len;
2419
2420	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
2421	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
2422	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
2423	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
2424	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
2425
2426	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0);
2427	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
2428	if(read_cb(buffer, 1, len, handle) != len)
2429		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2430	block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
2431
2432	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2433		return status;
2434
2435	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2436		return status;
2437
2438	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0);
2439	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
2440	if(read_cb(buffer, 1, len, handle) != len)
2441		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2442	block->width = unpack_uint32_(buffer, len);
2443
2444	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0);
2445	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
2446	if(read_cb(buffer, 1, len, handle) != len)
2447		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2448	block->height = unpack_uint32_(buffer, len);
2449
2450	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0);
2451	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
2452	if(read_cb(buffer, 1, len, handle) != len)
2453		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2454	block->depth = unpack_uint32_(buffer, len);
2455
2456	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0);
2457	len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
2458	if(read_cb(buffer, 1, len, handle) != len)
2459		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2460	block->colors = unpack_uint32_(buffer, len);
2461
2462	/* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
2463	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
2464		return status;
2465
2466	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2467}
2468
2469FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length)
2470{
2471	if(block_length == 0) {
2472		block->data = 0;
2473	}
2474	else {
2475		if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
2476			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2477
2478		if(read_cb(block->data, 1, block_length, handle) != block_length)
2479			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
2480	}
2481
2482	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2483}
2484
2485FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
2486{
2487	FLAC__ASSERT(0 != file);
2488	FLAC__ASSERT(0 != status);
2489
2490	if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
2491		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2492		return false;
2493	}
2494
2495	return true;
2496}
2497
2498FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
2499{
2500	FLAC__ASSERT(0 != file);
2501	FLAC__ASSERT(0 != status);
2502
2503	if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
2504		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
2505		return true;
2506	}
2507	else {
2508		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
2509		return false;
2510	}
2511}
2512
2513FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
2514{
2515	FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
2516
2517	FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
2518
2519	buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
2520	pack_uint32_(block->length, buffer + 1, 3);
2521
2522	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
2523		return false;
2524
2525	return true;
2526}
2527
2528FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
2529{
2530	FLAC__ASSERT(0 != block);
2531
2532	switch(block->type) {
2533		case FLAC__METADATA_TYPE_STREAMINFO:
2534			return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
2535		case FLAC__METADATA_TYPE_PADDING:
2536			return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
2537		case FLAC__METADATA_TYPE_APPLICATION:
2538			return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
2539		case FLAC__METADATA_TYPE_SEEKTABLE:
2540			return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
2541		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
2542			return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
2543		case FLAC__METADATA_TYPE_CUESHEET:
2544			return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
2545		case FLAC__METADATA_TYPE_PICTURE:
2546			return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
2547		default:
2548			return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
2549	}
2550}
2551
2552FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
2553{
2554	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
2555	const unsigned channels1 = block->channels - 1;
2556	const unsigned bps1 = block->bits_per_sample - 1;
2557
2558	/* we are using hardcoded numbers for simplicity but we should
2559	 * probably eventually write a bit-level packer and use the
2560	 * _STREAMINFO_ constants.
2561	 */
2562	pack_uint32_(block->min_blocksize, buffer, 2);
2563	pack_uint32_(block->max_blocksize, buffer+2, 2);
2564	pack_uint32_(block->min_framesize, buffer+4, 3);
2565	pack_uint32_(block->max_framesize, buffer+7, 3);
2566	buffer[10] = (block->sample_rate >> 12) & 0xff;
2567	buffer[11] = (block->sample_rate >> 4) & 0xff;
2568	buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
2569	buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
2570	pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
2571	memcpy(buffer+18, block->md5sum, 16);
2572
2573	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
2574		return false;
2575
2576	return true;
2577}
2578
2579FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
2580{
2581	unsigned i, n = block_length;
2582	FLAC__byte buffer[1024];
2583
2584	(void)block;
2585
2586	memset(buffer, 0, 1024);
2587
2588	for(i = 0; i < n/1024; i++)
2589		if(write_cb(buffer, 1, 1024, handle) != 1024)
2590			return false;
2591
2592	n %= 1024;
2593
2594	if(write_cb(buffer, 1, n, handle) != n)
2595		return false;
2596
2597	return true;
2598}
2599
2600FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length)
2601{
2602	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
2603
2604	if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
2605		return false;
2606
2607	block_length -= id_bytes;
2608
2609	if(write_cb(block->data, 1, block_length, handle) != block_length)
2610		return false;
2611
2612	return true;
2613}
2614
2615FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
2616{
2617	unsigned i;
2618	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
2619
2620	for(i = 0; i < block->num_points; i++) {
2621		/* some MAGIC NUMBERs here */
2622		pack_uint64_(block->points[i].sample_number, buffer, 8);
2623		pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
2624		pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
2625		if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
2626			return false;
2627	}
2628
2629	return true;
2630}
2631
2632FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
2633{
2634	unsigned i;
2635	const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
2636	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
2637	FLAC__byte buffer[4]; /* magic number is asserted below */
2638
2639	FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer));
2640
2641	pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
2642	if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
2643		return false;
2644	if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
2645		return false;
2646
2647	pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
2648	if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
2649		return false;
2650
2651	for(i = 0; i < block->num_comments; i++) {
2652		pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
2653		if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
2654			return false;
2655		if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
2656			return false;
2657	}
2658
2659	return true;
2660}
2661
2662FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
2663{
2664	unsigned i, j, len;
2665	FLAC__byte buffer[1024]; /* asserted below that this is big enough */
2666
2667	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
2668	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
2669	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);
2670	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
2671
2672	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
2673	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
2674	if(write_cb(block->media_catalog_number, 1, len, handle) != len)
2675		return false;
2676
2677	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
2678	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
2679	pack_uint64_(block->lead_in, buffer, len);
2680	if(write_cb(buffer, 1, len, handle) != len)
2681		return false;
2682
2683	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
2684	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
2685	memset(buffer, 0, len);
2686	if(block->is_cd)
2687		buffer[0] |= 0x80;
2688	if(write_cb(buffer, 1, len, handle) != len)
2689		return false;
2690
2691	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
2692	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
2693	pack_uint32_(block->num_tracks, buffer, len);
2694	if(write_cb(buffer, 1, len, handle) != len)
2695		return false;
2696
2697	for(i = 0; i < block->num_tracks; i++) {
2698		FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
2699
2700		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
2701		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
2702		pack_uint64_(track->offset, buffer, len);
2703		if(write_cb(buffer, 1, len, handle) != len)
2704			return false;
2705
2706		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
2707		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
2708		pack_uint32_(track->number, buffer, len);
2709		if(write_cb(buffer, 1, len, handle) != len)
2710			return false;
2711
2712		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
2713		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
2714		if(write_cb(track->isrc, 1, len, handle) != len)
2715			return false;
2716
2717		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);
2718		len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
2719		memset(buffer, 0, len);
2720		buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
2721		if(write_cb(buffer, 1, len, handle) != len)
2722			return false;
2723
2724		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
2725		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
2726		pack_uint32_(track->num_indices, buffer, len);
2727		if(write_cb(buffer, 1, len, handle) != len)
2728			return false;
2729
2730		for(j = 0; j < track->num_indices; j++) {
2731			FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
2732
2733			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
2734			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
2735			pack_uint64_(index->offset, buffer, len);
2736			if(write_cb(buffer, 1, len, handle) != len)
2737				return false;
2738
2739			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
2740			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
2741			pack_uint32_(index->number, buffer, len);
2742			if(write_cb(buffer, 1, len, handle) != len)
2743				return false;
2744
2745			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
2746			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
2747			memset(buffer, 0, len);
2748			if(write_cb(buffer, 1, len, handle) != len)
2749				return false;
2750		}
2751	}
2752
2753	return true;
2754}
2755
2756FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
2757{
2758	unsigned len;
2759	size_t slen;
2760	FLAC__byte buffer[4]; /* magic number is asserted below */
2761
2762	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8);
2763	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8);
2764	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8);
2765	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8);
2766	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8);
2767	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8);
2768	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8);
2769	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8);
2770	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
2771	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8);
2772	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8);
2773	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
2774	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
2775	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
2776	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
2777	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8);
2778
2779	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
2780	pack_uint32_(block->type, buffer, len);
2781	if(write_cb(buffer, 1, len, handle) != len)
2782		return false;
2783
2784	len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
2785	slen = strlen(block->mime_type);
2786	pack_uint32_(slen, buffer, len);
2787	if(write_cb(buffer, 1, len, handle) != len)
2788		return false;
2789	if(write_cb(block->mime_type, 1, slen, handle) != slen)
2790		return false;
2791
2792	len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
2793	slen = strlen((const char *)block->description);
2794	pack_uint32_(slen, buffer, len);
2795	if(write_cb(buffer, 1, len, handle) != len)
2796		return false;
2797	if(write_cb(block->description, 1, slen, handle) != slen)
2798		return false;
2799
2800	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
2801	pack_uint32_(block->width, buffer, len);
2802	if(write_cb(buffer, 1, len, handle) != len)
2803		return false;
2804
2805	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
2806	pack_uint32_(block->height, buffer, len);
2807	if(write_cb(buffer, 1, len, handle) != len)
2808		return false;
2809
2810	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
2811	pack_uint32_(block->depth, buffer, len);
2812	if(write_cb(buffer, 1, len, handle) != len)
2813		return false;
2814
2815	len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
2816	pack_uint32_(block->colors, buffer, len);
2817	if(write_cb(buffer, 1, len, handle) != len)
2818		return false;
2819
2820	len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
2821	pack_uint32_(block->data_length, buffer, len);
2822	if(write_cb(buffer, 1, len, handle) != len)
2823		return false;
2824	if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
2825		return false;
2826
2827	return true;
2828}
2829
2830FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
2831{
2832	if(write_cb(block->data, 1, block_length, handle) != block_length)
2833		return false;
2834
2835	return true;
2836}
2837
2838FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
2839{
2840	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2841		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2842		return false;
2843	}
2844
2845	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
2846		return false;
2847
2848	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
2849		return false;
2850
2851	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2852		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2853		return false;
2854	}
2855
2856	return read_metadata_block_header_(iterator);
2857}
2858
2859FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last)
2860{
2861	FLAC__StreamMetadata *padding;
2862
2863	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2864		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2865		return false;
2866	}
2867
2868	block->is_last = false;
2869
2870	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
2871		return false;
2872
2873	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
2874		return false;
2875
2876	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
2877		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
2878
2879	padding->is_last = padding_is_last;
2880	padding->length = padding_length;
2881
2882	if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
2883		FLAC__metadata_object_delete(padding);
2884		return false;
2885	}
2886
2887	if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
2888		FLAC__metadata_object_delete(padding);
2889		return false;
2890	}
2891
2892	FLAC__metadata_object_delete(padding);
2893
2894	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2895		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2896		return false;
2897	}
2898
2899	return read_metadata_block_header_(iterator);
2900}
2901
2902FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
2903{
2904	FILE *tempfile;
2905	char *tempfilename;
2906	int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
2907	off_t fixup_is_last_flag_offset = -1;
2908
2909	FLAC__ASSERT(0 != block || append == false);
2910
2911	if(iterator->is_last) {
2912		if(append) {
2913			fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
2914			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
2915		}
2916		else if(0 == block) {
2917			simple_iterator_push_(iterator);
2918			if(!FLAC__metadata_simple_iterator_prev(iterator)) {
2919				(void)simple_iterator_pop_(iterator);
2920				return false;
2921			}
2922			fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
2923			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
2924			if(!simple_iterator_pop_(iterator))
2925				return false;
2926		}
2927	}
2928
2929	if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
2930		return false;
2931
2932	if(0 != block) {
2933		if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
2934			cleanup_tempfile_(&tempfile, &tempfilename);
2935			return false;
2936		}
2937
2938		if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
2939			cleanup_tempfile_(&tempfile, &tempfilename);
2940			return false;
2941		}
2942	}
2943
2944	if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
2945		return false;
2946
2947	if(append)
2948		return FLAC__metadata_simple_iterator_next(iterator);
2949
2950	return true;
2951}
2952
2953void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
2954{
2955	FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
2956	iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
2957	iterator->depth++;
2958}
2959
2960FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
2961{
2962	FLAC__ASSERT(iterator->depth > 0);
2963	iterator->depth--;
2964	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
2965		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
2966		return false;
2967	}
2968
2969	return read_metadata_block_header_(iterator);
2970}
2971
2972/* return meanings:
2973 * 0: ok
2974 * 1: read error
2975 * 2: seek error
2976 * 3: not a FLAC file
2977 */
2978unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
2979{
2980	FLAC__byte buffer[4];
2981	size_t n;
2982	unsigned i;
2983
2984	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
2985
2986	/* skip any id3v2 tag */
2987	errno = 0;
2988	n = read_cb(buffer, 1, 4, handle);
2989	if(errno)
2990		return 1;
2991	else if(n != 4)
2992		return 3;
2993	else if(0 == memcmp(buffer, "ID3", 3)) {
2994		unsigned tag_length = 0;
2995
2996		/* skip to the tag length */
2997		if(seek_cb(handle, 2, SEEK_CUR) < 0)
2998			return 2;
2999
3000		/* read the length */
3001		for(i = 0; i < 4; i++) {
3002			if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
3003				return 1;
3004			tag_length <<= 7;
3005			tag_length |= (buffer[0] & 0x7f);
3006		}
3007
3008		/* skip the rest of the tag */
3009		if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
3010			return 2;
3011
3012		/* read the stream sync code */
3013		errno = 0;
3014		n = read_cb(buffer, 1, 4, handle);
3015		if(errno)
3016			return 1;
3017		else if(n != 4)
3018			return 3;
3019	}
3020
3021	/* check for the fLaC signature */
3022	if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
3023		return 0;
3024	else
3025		return 3;
3026}
3027
3028unsigned seek_to_first_metadata_block_(FILE *f)
3029{
3030	return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
3031}
3032
3033FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
3034{
3035	const off_t offset_end = append? iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length : iterator->offset[iterator->depth];
3036
3037	if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
3038		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
3039		return false;
3040	}
3041	if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
3042		cleanup_tempfile_(tempfile, tempfilename);
3043		return false;
3044	}
3045	if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
3046		cleanup_tempfile_(tempfile, tempfilename);
3047		return false;
3048	}
3049
3050	return true;
3051}
3052
3053FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, off_t fixup_is_last_flag_offset, FLAC__bool backup)
3054{
3055	off_t save_offset = iterator->offset[iterator->depth];
3056	FLAC__ASSERT(0 != *tempfile);
3057
3058	if(0 != fseeko(iterator->file, save_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length, SEEK_SET)) {
3059		cleanup_tempfile_(tempfile, tempfilename);
3060		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
3061		return false;
3062	}
3063	if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
3064		cleanup_tempfile_(tempfile, tempfilename);
3065		return false;
3066	}
3067
3068	if(fixup_is_last_code != 0) {
3069		/*
3070		 * if code == 1, it means a block was appended to the end so
3071		 *   we have to clear the is_last flag of the previous block
3072		 * if code == -1, it means the last block was deleted so
3073		 *   we have to set the is_last flag of the previous block
3074		 */
3075		/* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
3076		FLAC__byte x;
3077		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
3078			cleanup_tempfile_(tempfile, tempfilename);
3079			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
3080			return false;
3081		}
3082		if(fread(&x, 1, 1, *tempfile) != 1) {
3083			cleanup_tempfile_(tempfile, tempfilename);
3084			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
3085			return false;
3086		}
3087		if(fixup_is_last_code > 0) {
3088			FLAC__ASSERT(x & 0x80);
3089			x &= 0x7f;
3090		}
3091		else {
3092			FLAC__ASSERT(!(x & 0x80));
3093			x |= 0x80;
3094		}
3095		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
3096			cleanup_tempfile_(tempfile, tempfilename);
3097			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
3098			return false;
3099		}
3100		if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
3101			cleanup_tempfile_(tempfile, tempfilename);
3102			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
3103			return false;
3104		}
3105	}
3106
3107	(void)fclose(iterator->file);
3108
3109	if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
3110		return false;
3111
3112	if(iterator->has_stats)
3113		set_file_stats_(iterator->filename, &iterator->stats);
3114
3115	if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
3116		return false;
3117	if(backup) {
3118		while(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length < save_offset)
3119			if(!FLAC__metadata_simple_iterator_next(iterator))
3120				return false;
3121		return true;
3122	}
3123	else {
3124		/* move the iterator to it's original block faster by faking a push, then doing a pop_ */
3125		FLAC__ASSERT(iterator->depth == 0);
3126		iterator->offset[0] = save_offset;
3127		iterator->depth++;
3128		return simple_iterator_pop_(iterator);
3129	}
3130}
3131
3132FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
3133{
3134	FLAC__byte buffer[8192];
3135	size_t n;
3136
3137	FLAC__ASSERT(bytes >= 0);
3138	while(bytes > 0) {
3139		n = min(sizeof(buffer), (size_t)bytes);
3140		if(fread(buffer, 1, n, file) != n) {
3141			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
3142			return false;
3143		}
3144		if(local__fwrite(buffer, 1, n, tempfile) != n) {
3145			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
3146			return false;
3147		}
3148		bytes -= n;
3149	}
3150
3151	return true;
3152}
3153
3154FLAC__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, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
3155{
3156	FLAC__byte buffer[8192];
3157	size_t n;
3158
3159	FLAC__ASSERT(bytes >= 0);
3160	while(bytes > 0) {
3161		n = min(sizeof(buffer), (size_t)bytes);
3162		if(read_cb(buffer, 1, n, handle) != n) {
3163			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
3164			return false;
3165		}
3166		if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
3167			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
3168			return false;
3169		}
3170		bytes -= n;
3171	}
3172
3173	return true;
3174}
3175
3176FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
3177{
3178	FLAC__byte buffer[8192];
3179	size_t n;
3180
3181	while(!feof(file)) {
3182		n = fread(buffer, 1, sizeof(buffer), file);
3183		if(n == 0 && !feof(file)) {
3184			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
3185			return false;
3186		}
3187		if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
3188			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
3189			return false;
3190		}
3191	}
3192
3193	return true;
3194}
3195
3196FLAC__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)
3197{
3198	FLAC__byte buffer[8192];
3199	size_t n;
3200
3201	while(!eof_cb(handle)) {
3202		n = read_cb(buffer, 1, sizeof(buffer), handle);
3203		if(n == 0 && !eof_cb(handle)) {
3204			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
3205			return false;
3206		}
3207		if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
3208			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
3209			return false;
3210		}
3211	}
3212
3213	return true;
3214}
3215
3216FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
3217{
3218	static const char *tempfile_suffix = ".metadata_edit";
3219	if(0 == tempfile_path_prefix) {
3220		if(0 == (*tempfilename = (char*)safe_malloc_add_3op_(strlen(filename), /*+*/strlen(tempfile_suffix), /*+*/1))) {
3221			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
3222			return false;
3223		}
3224		strcpy(*tempfilename, filename);
3225		strcat(*tempfilename, tempfile_suffix);
3226	}
3227	else {
3228		const char *p = strrchr(filename, '/');
3229		if(0 == p)
3230			p = filename;
3231		else
3232			p++;
3233
3234		if(0 == (*tempfilename = (char*)safe_malloc_add_4op_(strlen(tempfile_path_prefix), /*+*/strlen(p), /*+*/strlen(tempfile_suffix), /*+*/2))) {
3235			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
3236			return false;
3237		}
3238		strcpy(*tempfilename, tempfile_path_prefix);
3239		strcat(*tempfilename, "/");
3240		strcat(*tempfilename, p);
3241		strcat(*tempfilename, tempfile_suffix);
3242	}
3243
3244	if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) {
3245		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
3246		return false;
3247	}
3248
3249	return true;
3250}
3251
3252FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
3253{
3254	FLAC__ASSERT(0 != filename);
3255	FLAC__ASSERT(0 != tempfile);
3256	FLAC__ASSERT(0 != *tempfile);
3257	FLAC__ASSERT(0 != tempfilename);
3258	FLAC__ASSERT(0 != *tempfilename);
3259	FLAC__ASSERT(0 != status);
3260
3261	(void)fclose(*tempfile);
3262	*tempfile = 0;
3263
3264#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
3265	/* on some flavors of windows, rename() will fail if the destination already exists */
3266	if(unlink(filename) < 0) {
3267		cleanup_tempfile_(tempfile, tempfilename);
3268		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
3269		return false;
3270	}
3271#endif
3272
3273	/*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just rename(): */
3274	if(0 != rename(*tempfilename, filename)) {
3275		cleanup_tempfile_(tempfile, tempfilename);
3276		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
3277		return false;
3278	}
3279
3280	cleanup_tempfile_(tempfile, tempfilename);
3281
3282	return true;
3283}
3284
3285void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
3286{
3287	if(0 != *tempfile) {
3288		(void)fclose(*tempfile);
3289		*tempfile = 0;
3290	}
3291
3292	if(0 != *tempfilename) {
3293		(void)unlink(*tempfilename);
3294		free(*tempfilename);
3295		*tempfilename = 0;
3296	}
3297}
3298
3299FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
3300{
3301	FLAC__ASSERT(0 != filename);
3302	FLAC__ASSERT(0 != stats);
3303	return (0 == stat(filename, stats));
3304}
3305
3306void set_file_stats_(const char *filename, struct stat *stats)
3307{
3308	struct utimbuf srctime;
3309
3310	FLAC__ASSERT(0 != filename);
3311	FLAC__ASSERT(0 != stats);
3312
3313	srctime.actime = stats->st_atime;
3314	srctime.modtime = stats->st_mtime;
3315	(void)chmod(filename, stats->st_mode);
3316	(void)utime(filename, &srctime);
3317#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__ && !defined __EMX__
3318	(void)chown(filename, stats->st_uid, -1);
3319	(void)chown(filename, -1, stats->st_gid);
3320#endif
3321}
3322
3323int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
3324{
3325	return fseeko((FILE*)handle, (off_t)offset, whence);
3326}
3327
3328FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
3329{
3330	return ftello((FILE*)handle);
3331}
3332
3333FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
3334{
3335	switch(status) {
3336		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
3337			return FLAC__METADATA_CHAIN_STATUS_OK;
3338		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
3339			return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
3340		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
3341			return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
3342		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
3343			return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
3344		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
3345			return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
3346		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
3347			return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
3348		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
3349			return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
3350		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
3351			return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
3352		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
3353			return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
3354		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
3355			return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
3356		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
3357			return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
3358		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
3359			return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
3360		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
3361		default:
3362			return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
3363	}
3364}
3365