1/* test_libFLAC - Unit tester for libFLAC
2 * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 */
18
19#if HAVE_CONFIG_H
20#  include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h> /* for malloc() */
25#include <string.h> /* for memcpy()/memset() */
26#if defined _MSC_VER || defined __MINGW32__
27#include <sys/utime.h> /* for utime() */
28#include <io.h> /* for chmod() */
29#if _MSC_VER <= 1600 /* @@@ [2G limit] */
30#define fseeko fseek
31#define ftello ftell
32#endif
33#else
34#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
35#include <utime.h> /* for utime() */
36#include <unistd.h> /* for chown(), unlink() */
37#endif
38#include <sys/stat.h> /* for stat(), maybe chmod() */
39#include "FLAC/assert.h"
40#include "FLAC/stream_decoder.h"
41#include "FLAC/metadata.h"
42#include "share/grabbag.h"
43#include "test_libs_common/file_utils_flac.h"
44#include "test_libs_common/metadata_utils.h"
45#include "metadata.h"
46
47
48/******************************************************************************
49	The general strategy of these tests (for interface levels 1 and 2) is
50	to create a dummy FLAC file with a known set of initial metadata
51	blocks, then keep a mirror locally of what we expect the metadata to be
52	after each operation.  Then testing becomes a simple matter of running
53	a FLAC__StreamDecoder over the dummy file after each operation, comparing
54	the decoded metadata to what's in our local copy.  If there are any
55	differences in the metadata, or the actual audio data is corrupted, we
56	will catch it while decoding.
57******************************************************************************/
58
59typedef struct {
60	FLAC__bool error_occurred;
61} decoder_client_struct;
62
63typedef struct {
64	FLAC__StreamMetadata *blocks[64];
65	unsigned num_blocks;
66} our_metadata_struct;
67
68/* our copy of the metadata in flacfilename() */
69static our_metadata_struct our_metadata_;
70
71/* the current block number that corresponds to the position of the iterator we are testing */
72static unsigned mc_our_block_number_ = 0;
73
74static const char *flacfilename(FLAC__bool is_ogg)
75{
76	return is_ogg? "metadata.oga" : "metadata.flac";
77}
78
79static FLAC__bool die_(const char *msg)
80{
81	printf("ERROR: %s\n", msg);
82	return false;
83}
84
85static FLAC__bool die_c_(const char *msg, FLAC__Metadata_ChainStatus status)
86{
87	printf("ERROR: %s\n", msg);
88	printf("       status=%s\n", FLAC__Metadata_ChainStatusString[status]);
89	return false;
90}
91
92static FLAC__bool die_ss_(const char *msg, FLAC__Metadata_SimpleIterator *iterator)
93{
94	printf("ERROR: %s\n", msg);
95	printf("       status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]);
96	return false;
97}
98
99static void *malloc_or_die_(size_t size)
100{
101	void *x = malloc(size);
102	if(0 == x) {
103		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
104		exit(1);
105	}
106	return x;
107}
108
109static char *strdup_or_die_(const char *s)
110{
111	char *x = strdup(s);
112	if(0 == x) {
113		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
114		exit(1);
115	}
116	return x;
117}
118
119/* functions for working with our metadata copy */
120
121static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
122{
123	unsigned i;
124	FLAC__StreamMetadata *obj = block;
125	FLAC__ASSERT(position < our_metadata_.num_blocks);
126	if(copy) {
127		if(0 == (obj = FLAC__metadata_object_clone(block)))
128			return die_("during FLAC__metadata_object_clone()");
129	}
130	FLAC__metadata_object_delete(our_metadata_.blocks[position]);
131	our_metadata_.blocks[position] = obj;
132
133	/* set the is_last flags */
134	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
135		our_metadata_.blocks[i]->is_last = false;
136	our_metadata_.blocks[i]->is_last = true;
137
138	return true;
139}
140
141static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
142{
143	unsigned i;
144	FLAC__StreamMetadata *obj = block;
145	if(copy) {
146		if(0 == (obj = FLAC__metadata_object_clone(block)))
147			return die_("during FLAC__metadata_object_clone()");
148	}
149	if(position > our_metadata_.num_blocks) {
150		position = our_metadata_.num_blocks;
151	}
152	else {
153		for(i = our_metadata_.num_blocks; i > position; i--)
154			our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
155	}
156	our_metadata_.blocks[position] = obj;
157	our_metadata_.num_blocks++;
158
159	/* set the is_last flags */
160	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
161		our_metadata_.blocks[i]->is_last = false;
162	our_metadata_.blocks[i]->is_last = true;
163
164	return true;
165}
166
167static void delete_from_our_metadata_(unsigned position)
168{
169	unsigned i;
170	FLAC__ASSERT(position < our_metadata_.num_blocks);
171	FLAC__metadata_object_delete(our_metadata_.blocks[position]);
172	for(i = position; i < our_metadata_.num_blocks - 1; i++)
173		our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
174	our_metadata_.num_blocks--;
175
176	/* set the is_last flags */
177	if(our_metadata_.num_blocks > 0) {
178		for(i = 0; i < our_metadata_.num_blocks - 1; i++)
179			our_metadata_.blocks[i]->is_last = false;
180		our_metadata_.blocks[i]->is_last = true;
181	}
182}
183
184/*
185 * This wad of functions supports filename- and callback-based chain reading/writing.
186 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
187 */
188static FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
189{
190	static const char *tempfile_suffix = ".metadata_edit";
191
192	if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
193		return false;
194	strcpy(*tempfilename, filename);
195	strcat(*tempfilename, tempfile_suffix);
196
197	if(0 == (*tempfile = fopen(*tempfilename, "wb")))
198		return false;
199
200	return true;
201}
202
203static void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
204{
205	if(0 != *tempfile) {
206		(void)fclose(*tempfile);
207		*tempfile = 0;
208	}
209
210	if(0 != *tempfilename) {
211		(void)unlink(*tempfilename);
212		free(*tempfilename);
213		*tempfilename = 0;
214	}
215}
216
217static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
218{
219	FLAC__ASSERT(0 != filename);
220	FLAC__ASSERT(0 != tempfile);
221	FLAC__ASSERT(0 != tempfilename);
222	FLAC__ASSERT(0 != *tempfilename);
223
224	if(0 != *tempfile) {
225		(void)fclose(*tempfile);
226		*tempfile = 0;
227	}
228
229#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
230	/* on some flavors of windows, rename() will fail if the destination already exists */
231	if(unlink(filename) < 0) {
232		cleanup_tempfile_(tempfile, tempfilename);
233		return false;
234	}
235#endif
236
237	if(0 != rename(*tempfilename, filename)) {
238		cleanup_tempfile_(tempfile, tempfilename);
239		return false;
240	}
241
242	cleanup_tempfile_(tempfile, tempfilename);
243
244	return true;
245}
246
247static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
248{
249	FLAC__ASSERT(0 != filename);
250	FLAC__ASSERT(0 != stats);
251	return (0 == stat(filename, stats));
252}
253
254static void set_file_stats_(const char *filename, struct stat *stats)
255{
256	struct utimbuf srctime;
257
258	FLAC__ASSERT(0 != filename);
259	FLAC__ASSERT(0 != stats);
260
261	srctime.actime = stats->st_atime;
262	srctime.modtime = stats->st_mtime;
263	(void)chmod(filename, stats->st_mode);
264	(void)utime(filename, &srctime);
265#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
266	(void)chown(filename, stats->st_uid, -1);
267	(void)chown(filename, -1, stats->st_gid);
268#endif
269}
270
271#ifdef FLAC__VALGRIND_TESTING
272static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
273{
274	FILE *stream = (FILE*)handle;
275	size_t ret = fwrite(ptr, size, nmemb, stream);
276	if(!ferror(stream))
277		fflush(stream);
278	return ret;
279}
280#endif
281
282static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
283{
284	off_t o = (off_t)offset;
285	FLAC__ASSERT(offset == o);
286	return fseeko((FILE*)handle, o, whence);
287}
288
289static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle)
290{
291	return ftello((FILE*)handle);
292}
293
294static int chain_eof_cb_(FLAC__IOHandle handle)
295{
296	return feof((FILE*)handle);
297}
298
299static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename)
300{
301	if(filename_based)
302		return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats);
303	else {
304		FLAC__IOCallbacks callbacks;
305
306		memset(&callbacks, 0, sizeof(callbacks));
307		callbacks.read = (FLAC__IOCallback_Read)fread;
308#ifdef FLAC__VALGRIND_TESTING
309		callbacks.write = chain_write_cb_;
310#else
311		callbacks.write = (FLAC__IOCallback_Write)fwrite;
312#endif
313		callbacks.seek = chain_seek_cb_;
314		callbacks.eof = chain_eof_cb_;
315
316		if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
317			struct stat stats;
318			FILE *file, *tempfile = 0;
319			char *tempfilename;
320			if(preserve_file_stats) {
321				if(!get_file_stats_(filename, &stats))
322					return false;
323			}
324			if(0 == (file = fopen(filename, "rb")))
325				return false; /*@@@@ chain status still says OK though */
326			if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
327				fclose(file);
328				cleanup_tempfile_(&tempfile, &tempfilename);
329				return false; /*@@@@ chain status still says OK though */
330			}
331			if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks)) {
332				fclose(file);
333				fclose(tempfile);
334				return false;
335			}
336			fclose(file);
337			fclose(tempfile);
338			file = tempfile = 0;
339			if(!transport_tempfile_(filename, &tempfile, &tempfilename))
340				return false;
341			if(preserve_file_stats)
342				set_file_stats_(filename, &stats);
343		}
344		else {
345			FILE *file = fopen(filename, "r+b");
346			if(0 == file)
347				return false; /*@@@@ chain status still says OK though */
348			if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks))
349				return false;
350			fclose(file);
351		}
352	}
353
354	return true;
355}
356
357static FLAC__bool read_chain_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based, FLAC__bool is_ogg)
358{
359	if(filename_based)
360		return is_ogg?
361			FLAC__metadata_chain_read_ogg(chain, flacfilename(is_ogg)) :
362			FLAC__metadata_chain_read(chain, flacfilename(is_ogg))
363		;
364	else {
365		FLAC__IOCallbacks callbacks;
366
367		memset(&callbacks, 0, sizeof(callbacks));
368		callbacks.read = (FLAC__IOCallback_Read)fread;
369		callbacks.seek = chain_seek_cb_;
370		callbacks.tell = chain_tell_cb_;
371
372		{
373			FLAC__bool ret;
374			FILE *file = fopen(filename, "rb");
375			if(0 == file)
376				return false; /*@@@@ chain status still says OK though */
377			ret = is_ogg?
378				FLAC__metadata_chain_read_ogg_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) :
379				FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)
380			;
381			fclose(file);
382			return ret;
383		}
384	}
385}
386
387/* function for comparing our metadata to a FLAC__Metadata_Chain */
388
389static FLAC__bool compare_chain_(FLAC__Metadata_Chain *chain, unsigned current_position, FLAC__StreamMetadata *current_block)
390{
391	unsigned i;
392	FLAC__Metadata_Iterator *iterator;
393	FLAC__StreamMetadata *block;
394	FLAC__bool next_ok = true;
395
396	FLAC__ASSERT(0 != chain);
397
398	printf("\tcomparing chain... ");
399	fflush(stdout);
400
401	if(0 == (iterator = FLAC__metadata_iterator_new()))
402		return die_("allocating memory for iterator");
403
404	FLAC__metadata_iterator_init(iterator, chain);
405
406	i = 0;
407	do {
408		printf("%u... ", i);
409		fflush(stdout);
410
411		if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
412			FLAC__metadata_iterator_delete(iterator);
413			return die_("getting block from iterator");
414		}
415
416		if(!mutils__compare_block(our_metadata_.blocks[i], block)) {
417			FLAC__metadata_iterator_delete(iterator);
418			return die_("metadata block mismatch");
419		}
420
421		i++;
422		next_ok = FLAC__metadata_iterator_next(iterator);
423	} while(i < our_metadata_.num_blocks && next_ok);
424
425	FLAC__metadata_iterator_delete(iterator);
426
427	if(next_ok)
428		return die_("chain has more blocks than expected");
429
430	if(i < our_metadata_.num_blocks)
431		return die_("short block count in chain");
432
433	if(0 != current_block) {
434		printf("CURRENT_POSITION... ");
435		fflush(stdout);
436
437		if(!mutils__compare_block(our_metadata_.blocks[current_position], current_block))
438			return die_("metadata block mismatch");
439	}
440
441	printf("PASSED\n");
442
443	return true;
444}
445
446/* decoder callbacks for checking the file */
447
448static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
449{
450	(void)decoder, (void)buffer, (void)client_data;
451
452	if(
453		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
454		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
455	) {
456		printf("content... ");
457		fflush(stdout);
458	}
459
460	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
461}
462
463/* this version pays no attention to the metadata */
464static void decoder_metadata_callback_null_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
465{
466	(void)decoder, (void)metadata, (void)client_data;
467
468	printf("%d... ", mc_our_block_number_);
469	fflush(stdout);
470
471	mc_our_block_number_++;
472}
473
474/* this version is used when we want to compare to our metadata copy */
475static void decoder_metadata_callback_compare_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
476{
477	decoder_client_struct *dcd = (decoder_client_struct*)client_data;
478
479	(void)decoder;
480
481	/* don't bother checking if we've already hit an error */
482	if(dcd->error_occurred)
483		return;
484
485	printf("%d... ", mc_our_block_number_);
486	fflush(stdout);
487
488	if(mc_our_block_number_ >= our_metadata_.num_blocks) {
489		(void)die_("got more metadata blocks than expected");
490		dcd->error_occurred = true;
491	}
492	else {
493		if(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) {
494			(void)die_("metadata block mismatch");
495			dcd->error_occurred = true;
496		}
497	}
498	mc_our_block_number_++;
499}
500
501static void decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
502{
503	decoder_client_struct *dcd = (decoder_client_struct*)client_data;
504	(void)decoder;
505
506	dcd->error_occurred = true;
507	printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
508}
509
510static FLAC__bool generate_file_(FLAC__bool include_extras, FLAC__bool is_ogg)
511{
512	FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
513	FLAC__StreamMetadata *metadata[4];
514	unsigned i = 0, n = 0;
515
516	printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
517
518	while(our_metadata_.num_blocks > 0)
519		delete_from_our_metadata_(0);
520
521	streaminfo.is_last = false;
522	streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
523	streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
524	streaminfo.data.stream_info.min_blocksize = 576;
525	streaminfo.data.stream_info.max_blocksize = 576;
526	streaminfo.data.stream_info.min_framesize = 0;
527	streaminfo.data.stream_info.max_framesize = 0;
528	streaminfo.data.stream_info.sample_rate = 44100;
529	streaminfo.data.stream_info.channels = 1;
530	streaminfo.data.stream_info.bits_per_sample = 8;
531	streaminfo.data.stream_info.total_samples = 0;
532	memset(streaminfo.data.stream_info.md5sum, 0, 16);
533
534	{
535		const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
536		vorbiscomment.is_last = false;
537		vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
538		vorbiscomment.length = (4 + vendor_string_length) + 4;
539		vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
540		vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
541		memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
542		vorbiscomment.data.vorbis_comment.num_comments = 0;
543		vorbiscomment.data.vorbis_comment.comments = 0;
544	}
545
546	{
547		if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)))
548			return die_("priming our metadata");
549		cuesheet->is_last = false;
550		strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
551		cuesheet->data.cue_sheet.lead_in = 123;
552		cuesheet->data.cue_sheet.is_cd = false;
553		if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
554			return die_("priming our metadata");
555		cuesheet->data.cue_sheet.tracks[0].number = 1;
556		if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
557			return die_("priming our metadata");
558	}
559
560	{
561		picture.is_last = false;
562		picture.type = FLAC__METADATA_TYPE_PICTURE;
563		picture.length =
564			(
565				FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
566				FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
567				FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
568				FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
569				FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
570				FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
571				FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
572				FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
573			) / 8
574		;
575		picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
576		picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
577		picture.length += strlen(picture.data.picture.mime_type);
578		picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
579		picture.length += strlen((const char *)picture.data.picture.description);
580		picture.data.picture.width = 300;
581		picture.data.picture.height = 300;
582		picture.data.picture.depth = 24;
583		picture.data.picture.colors = 0;
584		picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
585		picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
586		picture.length += picture.data.picture.data_length;
587	}
588
589	padding.is_last = true;
590	padding.type = FLAC__METADATA_TYPE_PADDING;
591	padding.length = 1234;
592
593	metadata[n++] = &vorbiscomment;
594	if(include_extras) {
595		metadata[n++] = cuesheet;
596		metadata[n++] = &picture;
597	}
598	metadata[n++] = &padding;
599
600	if(
601		!insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
602		!insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
603		(include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
604		(include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
605		!insert_to_our_metadata_(&padding, i++, /*copy=*/true)
606	)
607		return die_("priming our metadata");
608
609	if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
610		return die_("creating the encoded file");
611
612	free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
613	free(picture.data.picture.mime_type);
614	free(picture.data.picture.description);
615	free(picture.data.picture.data);
616	if(!include_extras)
617		FLAC__metadata_object_delete(cuesheet);
618
619	return true;
620}
621
622static FLAC__bool test_file_(FLAC__bool is_ogg, FLAC__StreamDecoderMetadataCallback metadata_callback)
623{
624	const char *filename = flacfilename(is_ogg);
625	FLAC__StreamDecoder *decoder;
626	decoder_client_struct decoder_client_data;
627
628	FLAC__ASSERT(0 != metadata_callback);
629
630	mc_our_block_number_ = 0;
631	decoder_client_data.error_occurred = false;
632
633	printf("\ttesting '%s'... ", filename);
634	fflush(stdout);
635
636	if(0 == (decoder = FLAC__stream_decoder_new()))
637		return die_("couldn't allocate decoder instance");
638
639	FLAC__stream_decoder_set_md5_checking(decoder, true);
640	FLAC__stream_decoder_set_metadata_respond_all(decoder);
641	if(
642		(is_ogg?
643			FLAC__stream_decoder_init_ogg_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) :
644			FLAC__stream_decoder_init_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data)
645		) != FLAC__STREAM_DECODER_INIT_STATUS_OK
646	) {
647		(void)FLAC__stream_decoder_finish(decoder);
648		FLAC__stream_decoder_delete(decoder);
649		return die_("initializing decoder\n");
650	}
651	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
652		(void)FLAC__stream_decoder_finish(decoder);
653		FLAC__stream_decoder_delete(decoder);
654		return die_("decoding file\n");
655	}
656
657	(void)FLAC__stream_decoder_finish(decoder);
658	FLAC__stream_decoder_delete(decoder);
659
660	if(decoder_client_data.error_occurred)
661		return false;
662
663	if(mc_our_block_number_ != our_metadata_.num_blocks)
664		return die_("short metadata block count");
665
666	printf("PASSED\n");
667	return true;
668}
669
670static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
671{
672	if(!grabbag__file_change_stats(filename, read_only))
673		return die_("during grabbag__file_change_stats()");
674
675	return true;
676}
677
678static FLAC__bool remove_file_(const char *filename)
679{
680	while(our_metadata_.num_blocks > 0)
681		delete_from_our_metadata_(0);
682
683	if(!grabbag__file_remove_file(filename))
684		return die_("removing file");
685
686	return true;
687}
688
689static FLAC__bool test_level_0_(void)
690{
691	FLAC__StreamMetadata streaminfo;
692	FLAC__StreamMetadata *tags = 0;
693	FLAC__StreamMetadata *cuesheet = 0;
694	FLAC__StreamMetadata *picture = 0;
695
696	printf("\n\n++++++ testing level 0 interface\n");
697
698	if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
699		return false;
700
701	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
702		return false;
703
704	printf("testing FLAC__metadata_get_streaminfo()... ");
705
706	if(!FLAC__metadata_get_streaminfo(flacfilename(/*is_ogg=*/false), &streaminfo))
707		return die_("during FLAC__metadata_get_streaminfo()");
708
709	/* check to see if some basic data matches (c.f. generate_file_()) */
710	if(streaminfo.data.stream_info.channels != 1)
711		return die_("mismatch in streaminfo.data.stream_info.channels");
712	if(streaminfo.data.stream_info.bits_per_sample != 8)
713		return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
714	if(streaminfo.data.stream_info.sample_rate != 44100)
715		return die_("mismatch in streaminfo.data.stream_info.sample_rate");
716	if(streaminfo.data.stream_info.min_blocksize != 576)
717		return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
718	if(streaminfo.data.stream_info.max_blocksize != 576)
719		return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
720
721	printf("OK\n");
722
723	printf("testing FLAC__metadata_get_tags()... ");
724
725	if(!FLAC__metadata_get_tags(flacfilename(/*is_ogg=*/false), &tags))
726		return die_("during FLAC__metadata_get_tags()");
727
728	/* check to see if some basic data matches (c.f. generate_file_()) */
729	if(tags->data.vorbis_comment.num_comments != 0)
730		return die_("mismatch in tags->data.vorbis_comment.num_comments");
731
732	printf("OK\n");
733
734	FLAC__metadata_object_delete(tags);
735
736	printf("testing FLAC__metadata_get_cuesheet()... ");
737
738	if(!FLAC__metadata_get_cuesheet(flacfilename(/*is_ogg=*/false), &cuesheet))
739		return die_("during FLAC__metadata_get_cuesheet()");
740
741	/* check to see if some basic data matches (c.f. generate_file_()) */
742	if(cuesheet->data.cue_sheet.lead_in != 123)
743		return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
744
745	printf("OK\n");
746
747	FLAC__metadata_object_delete(cuesheet);
748
749	printf("testing FLAC__metadata_get_picture()... ");
750
751	if(!FLAC__metadata_get_picture(flacfilename(/*is_ogg=*/false), &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
752		return die_("during FLAC__metadata_get_picture()");
753
754	/* check to see if some basic data matches (c.f. generate_file_()) */
755	if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
756		return die_("mismatch in picture->data.picture.type");
757
758	printf("OK\n");
759
760	FLAC__metadata_object_delete(picture);
761
762	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
763		return false;
764
765	return true;
766}
767
768static FLAC__bool test_level_1_(void)
769{
770	FLAC__Metadata_SimpleIterator *iterator;
771	FLAC__StreamMetadata *block, *app, *padding;
772	FLAC__byte data[1000];
773	unsigned our_current_position = 0;
774
775	/* initialize 'data' to avoid Valgrind errors */
776	memset(data, 0, sizeof(data));
777
778	printf("\n\n++++++ testing level 1 interface\n");
779
780	/************************************************************/
781
782	printf("simple iterator on read-only file\n");
783
784	if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
785		return false;
786
787	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
788		return false;
789
790	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
791		return false;
792
793	if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
794		return die_("FLAC__metadata_simple_iterator_new()");
795
796	if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
797		return die_("FLAC__metadata_simple_iterator_init() returned false");
798
799	printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
800	if(FLAC__metadata_simple_iterator_is_writable(iterator))
801		return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
802
803	printf("iterate forwards\n");
804
805	if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO)
806		return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
807	if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
808		return die_("getting block 0");
809	if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
810		return die_("expected STREAMINFO type");
811	if(block->is_last)
812		return die_("expected is_last to be false");
813	if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
814		return die_("bad STREAMINFO length");
815	/* check to see if some basic data matches (c.f. generate_file_()) */
816	if(block->data.stream_info.channels != 1)
817		return die_("mismatch in channels");
818	if(block->data.stream_info.bits_per_sample != 8)
819		return die_("mismatch in bits_per_sample");
820	if(block->data.stream_info.sample_rate != 44100)
821		return die_("mismatch in sample_rate");
822	if(block->data.stream_info.min_blocksize != 576)
823		return die_("mismatch in min_blocksize");
824	if(block->data.stream_info.max_blocksize != 576)
825		return die_("mismatch in max_blocksize");
826	FLAC__metadata_object_delete(block);
827
828	if(!FLAC__metadata_simple_iterator_next(iterator))
829		return die_("forward iterator ended early");
830	our_current_position++;
831
832	if(!FLAC__metadata_simple_iterator_next(iterator))
833		return die_("forward iterator ended early");
834	our_current_position++;
835
836	if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING)
837		return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
838	if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
839		return die_("getting block 2");
840	if(block->type != FLAC__METADATA_TYPE_PADDING)
841		return die_("expected PADDING type");
842	if(!block->is_last)
843		return die_("expected is_last to be true");
844	/* check to see if some basic data matches (c.f. generate_file_()) */
845	if(block->length != 1234)
846		return die_("bad PADDING length");
847	FLAC__metadata_object_delete(block);
848
849	if(FLAC__metadata_simple_iterator_next(iterator))
850		return die_("forward iterator returned true but should have returned false");
851
852	printf("iterate backwards\n");
853	if(!FLAC__metadata_simple_iterator_prev(iterator))
854		return die_("reverse iterator ended early");
855	if(!FLAC__metadata_simple_iterator_prev(iterator))
856		return die_("reverse iterator ended early");
857	if(FLAC__metadata_simple_iterator_prev(iterator))
858		return die_("reverse iterator returned true but should have returned false");
859
860	printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
861
862	if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false))
863		printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
864	else
865		return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
866
867	FLAC__metadata_simple_iterator_delete(iterator);
868
869	/************************************************************/
870
871	printf("simple iterator on writable file\n");
872
873	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
874		return false;
875
876	printf("creating APPLICATION block\n");
877
878	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
879		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
880	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
881
882	printf("creating PADDING block\n");
883
884	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
885		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
886	padding->length = 20;
887
888	if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
889		return die_("FLAC__metadata_simple_iterator_new()");
890
891	if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
892		return die_("FLAC__metadata_simple_iterator_init() returned false");
893	our_current_position = 0;
894
895	printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
896
897	printf("[S]VP\ttry to write over STREAMINFO block...\n");
898	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
899		printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
900	else
901		return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
902
903	printf("[S]VP\tnext\n");
904	if(!FLAC__metadata_simple_iterator_next(iterator))
905		return die_("iterator ended early\n");
906	our_current_position++;
907
908	printf("S[V]P\tnext\n");
909	if(!FLAC__metadata_simple_iterator_next(iterator))
910		return die_("iterator ended early\n");
911	our_current_position++;
912
913	printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
914	padding->length = 25;
915	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
916		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
917	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
918		return false;
919
920	printf("SVP[P]\tprev\n");
921	if(!FLAC__metadata_simple_iterator_prev(iterator))
922		return die_("iterator ended early\n");
923	our_current_position--;
924
925	printf("SV[P]P\tprev\n");
926	if(!FLAC__metadata_simple_iterator_prev(iterator))
927		return die_("iterator ended early\n");
928	our_current_position--;
929
930	printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
931	padding->length = 30;
932	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
933		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
934	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
935		return false;
936
937	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
938		return false;
939
940	printf("SV[P]PP\tprev\n");
941	if(!FLAC__metadata_simple_iterator_prev(iterator))
942		return die_("iterator ended early\n");
943	our_current_position--;
944
945	printf("S[V]PPP\tprev\n");
946	if(!FLAC__metadata_simple_iterator_prev(iterator))
947		return die_("iterator ended early\n");
948	our_current_position--;
949
950	printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
951	if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
952		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
953
954	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
955		return false;
956
957	printf("[S]VPPP\tnext\n");
958	if(!FLAC__metadata_simple_iterator_next(iterator))
959		return die_("iterator ended early\n");
960	our_current_position++;
961
962	printf("S[V]PPP\tnext\n");
963	if(!FLAC__metadata_simple_iterator_next(iterator))
964		return die_("iterator ended early\n");
965	our_current_position++;
966
967	printf("SV[P]PP\tdelete (middle block), replace with padding\n");
968	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
969		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
970	our_current_position--;
971
972	printf("S[V]PPP\tnext\n");
973	if(!FLAC__metadata_simple_iterator_next(iterator))
974		return die_("iterator ended early\n");
975	our_current_position++;
976
977	printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
978	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
979		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
980	delete_from_our_metadata_(our_current_position--);
981
982	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
983		return false;
984
985	printf("S[V]PP\tnext\n");
986	if(!FLAC__metadata_simple_iterator_next(iterator))
987		return die_("iterator ended early\n");
988	our_current_position++;
989
990	printf("SV[P]P\tnext\n");
991	if(!FLAC__metadata_simple_iterator_next(iterator))
992		return die_("iterator ended early\n");
993	our_current_position++;
994
995	printf("SVP[P]\tdelete (last block), replace with padding\n");
996	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
997		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
998	our_current_position--;
999
1000	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1001		return false;
1002
1003	printf("SV[P]P\tnext\n");
1004	if(!FLAC__metadata_simple_iterator_next(iterator))
1005		return die_("iterator ended early\n");
1006	our_current_position++;
1007
1008	printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1009	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1010		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1011	delete_from_our_metadata_(our_current_position--);
1012
1013	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1014		return false;
1015
1016	printf("SV[P]\tprev\n");
1017	if(!FLAC__metadata_simple_iterator_prev(iterator))
1018		return die_("iterator ended early\n");
1019	our_current_position--;
1020
1021	printf("S[V]P\tprev\n");
1022	if(!FLAC__metadata_simple_iterator_prev(iterator))
1023		return die_("iterator ended early\n");
1024	our_current_position--;
1025
1026	printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1027	FLAC__ASSERT(our_current_position == 0);
1028	block = FLAC__metadata_simple_iterator_get_block(iterator);
1029	block->data.stream_info.sample_rate = 32000;
1030	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1031		return die_("copying object");
1032	if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
1033		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
1034	FLAC__metadata_object_delete(block);
1035
1036	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1037		return false;
1038
1039	printf("[S]VP\tnext\n");
1040	if(!FLAC__metadata_simple_iterator_next(iterator))
1041		return die_("iterator ended early\n");
1042	our_current_position++;
1043
1044	printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1045	app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
1046	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1047		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1048	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1049		return false;
1050	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1051
1052	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1053		return false;
1054
1055	printf("SV[A]P\tnext\n");
1056	if(!FLAC__metadata_simple_iterator_next(iterator))
1057		return die_("iterator ended early\n");
1058	our_current_position++;
1059
1060	printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1061	app->data.application.id[0] = 'f'; /* twiddle the id */
1062	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1063		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1064	if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1065		return false;
1066	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1067
1068	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1069		return false;
1070
1071	printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1072	app->data.application.id[0] = 'g'; /* twiddle the id */
1073	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1074		return die_("setting APPLICATION data");
1075	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1076		return die_("copying object");
1077	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1078		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1079
1080	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1081		return false;
1082
1083	printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1084	app->data.application.id[0] = 'h'; /* twiddle the id */
1085	if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
1086		return die_("setting APPLICATION data");
1087	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1088		return die_("copying object");
1089	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1090		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1091
1092	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1093		return false;
1094
1095	printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1096	app->data.application.id[0] = 'i'; /* twiddle the id */
1097	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1098		return die_("setting APPLICATION data");
1099	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1100		return die_("copying object");
1101	our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
1102	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1103		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1104
1105	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1106		return false;
1107
1108	printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1109	app->data.application.id[0] = 'j'; /* twiddle the id */
1110	if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
1111		return die_("setting APPLICATION data");
1112	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1113		return die_("copying object");
1114	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1115		return die_("copying object");
1116	our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
1117	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1118		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1119
1120	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1121		return false;
1122
1123	printf("SVA[A]PP\tnext\n");
1124	if(!FLAC__metadata_simple_iterator_next(iterator))
1125		return die_("iterator ended early\n");
1126	our_current_position++;
1127
1128	printf("SVAA[P]P\tnext\n");
1129	if(!FLAC__metadata_simple_iterator_next(iterator))
1130		return die_("iterator ended early\n");
1131	our_current_position++;
1132
1133	printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1134	padding->length = 5;
1135	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1136		return die_("copying object");
1137	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1138		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1139
1140	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1141		return false;
1142
1143	printf("SVAAP[P]\tset APPLICATION (grow)\n");
1144	app->data.application.id[0] = 'k'; /* twiddle the id */
1145	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1146		return die_("copying object");
1147	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1148		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1149
1150	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1151		return false;
1152
1153	printf("SVAAP[A]\tset PADDING (equal)\n");
1154	padding->length = 27;
1155	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1156		return die_("copying object");
1157	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1158		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1159
1160	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1161		return false;
1162
1163	printf("SVAAP[P]\tprev\n");
1164	if(!FLAC__metadata_simple_iterator_prev(iterator))
1165		return die_("iterator ended early\n");
1166	our_current_position--;
1167
1168	printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1169	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1170		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1171	delete_from_our_metadata_(our_current_position--);
1172
1173	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1174		return false;
1175
1176	printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1177	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1178		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1179	delete_from_our_metadata_(our_current_position--);
1180
1181	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1182		return false;
1183
1184	printf("SV[A]P\tnext\n");
1185	if(!FLAC__metadata_simple_iterator_next(iterator))
1186		return die_("iterator ended early\n");
1187	our_current_position++;
1188
1189	printf("SVA[P]\tinsert PADDING after\n");
1190	padding->length = 5;
1191	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1192		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1193	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1194		return false;
1195
1196	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1197		return false;
1198
1199	printf("SVAP[P]\tprev\n");
1200	if(!FLAC__metadata_simple_iterator_prev(iterator))
1201		return die_("iterator ended early\n");
1202	our_current_position--;
1203
1204	printf("SVA[P]P\tprev\n");
1205	if(!FLAC__metadata_simple_iterator_prev(iterator))
1206		return die_("iterator ended early\n");
1207	our_current_position--;
1208
1209	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1210	if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
1211		return die_("setting APPLICATION data");
1212	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1213		return die_("copying object");
1214	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1215		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1216
1217	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1218		return false;
1219
1220	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1221	if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
1222		return die_("setting APPLICATION data");
1223	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1224		return die_("copying object");
1225	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1226		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1227
1228	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1229		return false;
1230
1231	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1232	if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
1233		return die_("setting APPLICATION data");
1234	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1235		return die_("copying object");
1236	our_metadata_.blocks[our_current_position+1]->length = 0;
1237	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1238		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1239
1240	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1241		return false;
1242
1243	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1244	if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
1245		return die_("setting APPLICATION data");
1246	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1247		return die_("copying object");
1248	delete_from_our_metadata_(our_current_position+1);
1249	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1250		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1251
1252	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1253		return false;
1254
1255	printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1256	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1257		return die_("setting APPLICATION data");
1258	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1259		return die_("copying object");
1260	delete_from_our_metadata_(our_current_position+1);
1261	our_metadata_.blocks[our_current_position]->is_last = true;
1262	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1263		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1264
1265	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1266		return false;
1267
1268	printf("SV[A]\tset PADDING (equal size)\n");
1269	padding->length = app->length;
1270	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1271		return die_("copying object");
1272	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
1273		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
1274
1275	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1276		return false;
1277
1278	printf("SV[P]\tinsert PADDING after\n");
1279	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1280		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1281	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1282		return false;
1283
1284	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1285		return false;
1286
1287	printf("SVP[P]\tinsert PADDING after\n");
1288	padding->length = 5;
1289	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1290		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1291	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1292		return false;
1293
1294	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1295		return false;
1296
1297	printf("SVPP[P]\tprev\n");
1298	if(!FLAC__metadata_simple_iterator_prev(iterator))
1299		return die_("iterator ended early\n");
1300	our_current_position--;
1301
1302	printf("SVP[P]P\tprev\n");
1303	if(!FLAC__metadata_simple_iterator_prev(iterator))
1304		return die_("iterator ended early\n");
1305	our_current_position--;
1306
1307	printf("SV[P]PP\tprev\n");
1308	if(!FLAC__metadata_simple_iterator_prev(iterator))
1309		return die_("iterator ended early\n");
1310	our_current_position--;
1311
1312	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1313	if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1314		return die_("setting APPLICATION data");
1315	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1316		return die_("copying object");
1317	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1318		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1319
1320	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1321		return false;
1322
1323	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1324	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1325		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1326	delete_from_our_metadata_(our_current_position--);
1327
1328	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1329		return false;
1330
1331	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1332	if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1333		return die_("setting APPLICATION data");
1334	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1335		return die_("copying object");
1336	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1337		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1338
1339	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1340		return false;
1341
1342	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1343	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1344		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1345	delete_from_our_metadata_(our_current_position--);
1346
1347	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1348		return false;
1349
1350	printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1351	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1352		return die_("setting APPLICATION data");
1353	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1354		return die_("copying object");
1355	delete_from_our_metadata_(our_current_position+1);
1356	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1357		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1358
1359	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1360		return false;
1361
1362	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1363	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1364		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1365	delete_from_our_metadata_(our_current_position--);
1366
1367	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1368		return false;
1369
1370	printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1371	if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1372		return die_("setting APPLICATION data");
1373	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1374		return die_("copying object");
1375	our_metadata_.blocks[our_current_position+1]->length = 0;
1376	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1377		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1378
1379	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1380		return false;
1381
1382	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1383	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1384		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1385	delete_from_our_metadata_(our_current_position--);
1386
1387	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1388		return false;
1389
1390	printf("S[V]PP\tnext\n");
1391	if(!FLAC__metadata_simple_iterator_next(iterator))
1392		return die_("iterator ended early\n");
1393	our_current_position++;
1394
1395	printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1396	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1397		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1398	delete_from_our_metadata_(our_current_position--);
1399
1400	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1401		return false;
1402
1403	printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1404	if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1405		return die_("setting APPLICATION data");
1406	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1407		return die_("copying object");
1408	delete_from_our_metadata_(our_current_position+1);
1409	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1410		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1411
1412	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1413		return false;
1414
1415	printf("delete simple iterator\n");
1416
1417	FLAC__metadata_simple_iterator_delete(iterator);
1418
1419	FLAC__metadata_object_delete(app);
1420	FLAC__metadata_object_delete(padding);
1421
1422	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1423		return false;
1424
1425	return true;
1426}
1427
1428static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
1429{
1430	FLAC__Metadata_Iterator *iterator;
1431	FLAC__Metadata_Chain *chain;
1432	FLAC__StreamMetadata *block, *app, *padding;
1433	FLAC__byte data[2000];
1434	unsigned our_current_position;
1435
1436	/* initialize 'data' to avoid Valgrind errors */
1437	memset(data, 0, sizeof(data));
1438
1439	printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1440
1441	printf("generate read-only file\n");
1442
1443	if(!generate_file_(/*include_extras=*/false, is_ogg))
1444		return false;
1445
1446	if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1447		return false;
1448
1449	printf("create chain\n");
1450
1451	if(0 == (chain = FLAC__metadata_chain_new()))
1452		return die_("allocating chain");
1453
1454	printf("read chain\n");
1455
1456	if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1457		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1458
1459	printf("[S]VP\ttest initial metadata\n");
1460
1461	if(!compare_chain_(chain, 0, 0))
1462		return false;
1463	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1464		return false;
1465
1466	if(is_ogg)
1467		goto end;
1468
1469	printf("switch file to read-write\n");
1470
1471	if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1472		return false;
1473
1474	printf("create iterator\n");
1475	if(0 == (iterator = FLAC__metadata_iterator_new()))
1476		return die_("allocating memory for iterator");
1477
1478	our_current_position = 0;
1479
1480	FLAC__metadata_iterator_init(iterator, chain);
1481
1482	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1483		return die_("getting block from iterator");
1484
1485	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1486
1487	printf("[S]VP\tmodify STREAMINFO, write\n");
1488
1489	block->data.stream_info.sample_rate = 32000;
1490	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1491		return die_("copying object");
1492
1493	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1494		return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1495	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1496		return false;
1497	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1498		return false;
1499
1500	printf("[S]VP\tnext\n");
1501	if(!FLAC__metadata_iterator_next(iterator))
1502		return die_("iterator ended early\n");
1503	our_current_position++;
1504
1505	printf("S[V]P\tnext\n");
1506	if(!FLAC__metadata_iterator_next(iterator))
1507		return die_("iterator ended early\n");
1508	our_current_position++;
1509
1510	printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1511	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1512		return die_("getting block from iterator");
1513	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1514		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1515	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1516	if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1517		return die_("setting APPLICATION data");
1518	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1519		return die_("copying object");
1520	if(!FLAC__metadata_iterator_set_block(iterator, app))
1521		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1522
1523	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1524		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1525	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1526		return false;
1527	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1528		return false;
1529
1530	printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1531	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1532		return die_("copying object");
1533	if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1534		return die_("setting APPLICATION data");
1535	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1536		return die_("copying object");
1537	if(!FLAC__metadata_iterator_set_block(iterator, app))
1538		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1539
1540	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1541		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1542	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1543		return false;
1544	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1545		return false;
1546
1547	printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1548	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1549		return die_("copying object");
1550	if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1551		return die_("setting APPLICATION data");
1552	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1553		return die_("copying object");
1554	if(!FLAC__metadata_iterator_set_block(iterator, app))
1555		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1556
1557	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1558		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1559	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1560		return false;
1561	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1562		return false;
1563
1564	printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1565	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1566		return die_("copying object");
1567	if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1568		return die_("setting APPLICATION data");
1569	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1570		return die_("copying object");
1571	if(!FLAC__metadata_iterator_set_block(iterator, app))
1572		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1573
1574	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1575		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1576	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1577		return false;
1578	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1579		return false;
1580
1581	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1582	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1583		return die_("copying object");
1584	if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1585		return die_("setting APPLICATION data");
1586	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1587		return die_("copying object");
1588	if(!FLAC__metadata_iterator_set_block(iterator, app))
1589		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1590
1591	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1592		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1593	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1594		return false;
1595	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1596		return false;
1597
1598	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1599	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1600		return die_("creating PADDING block");
1601	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1602		return die_("copying object");
1603	if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1604		return die_("setting APPLICATION data");
1605	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1606		return die_("copying object");
1607	padding->length = 0;
1608	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1609		return die_("internal error");
1610	if(!FLAC__metadata_iterator_set_block(iterator, app))
1611		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1612
1613	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1614		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1615	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1616		return false;
1617	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1618		return false;
1619
1620	printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1621	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1622		return die_("copying object");
1623	if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1624		return die_("setting APPLICATION data");
1625	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1626		return die_("copying object");
1627	our_metadata_.blocks[our_current_position+1]->length = 13;
1628	if(!FLAC__metadata_iterator_set_block(iterator, app))
1629		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1630
1631	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1632		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1633	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1634		return false;
1635	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1636		return false;
1637
1638	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1639	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1640		return die_("copying object");
1641	if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1642		return die_("setting APPLICATION data");
1643	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1644		return die_("copying object");
1645	if(!FLAC__metadata_iterator_set_block(iterator, app))
1646		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1647
1648	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1649		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1650	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1651		return false;
1652	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1653		return false;
1654
1655	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1656	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1657		return die_("copying object");
1658	if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1659		return die_("setting APPLICATION data");
1660	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1661		return die_("copying object");
1662	our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1663	if(!FLAC__metadata_iterator_set_block(iterator, app))
1664		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1665
1666	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1667		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1668	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1669		return false;
1670	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1671		return false;
1672
1673	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1674	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1675		return die_("copying object");
1676	if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1677		return die_("setting APPLICATION data");
1678	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1679		return die_("copying object");
1680	delete_from_our_metadata_(our_current_position+1);
1681	if(!FLAC__metadata_iterator_set_block(iterator, app))
1682		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1683
1684	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1685		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1686	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1687		return false;
1688	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1689		return false;
1690
1691	printf("SV[A]\tprev\n");
1692	if(!FLAC__metadata_iterator_prev(iterator))
1693		return die_("iterator ended early\n");
1694	our_current_position--;
1695
1696	printf("S[V]A\tprev\n");
1697	if(!FLAC__metadata_iterator_prev(iterator))
1698		return die_("iterator ended early\n");
1699	our_current_position--;
1700
1701	printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1702	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1703		return die_("creating PADDING block");
1704	padding->length = 30;
1705	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1706		printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1707	else
1708		return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1709
1710	printf("[S]VP\tnext\n");
1711	if(!FLAC__metadata_iterator_next(iterator))
1712		return die_("iterator ended early\n");
1713	our_current_position++;
1714
1715	printf("S[V]A\tinsert PADDING after\n");
1716	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1717		return die_("copying metadata");
1718	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1719		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1720
1721	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1722		return false;
1723
1724	printf("SV[P]A\tinsert PADDING before\n");
1725	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1726		return die_("creating PADDING block");
1727	padding->length = 17;
1728	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1729		return die_("copying metadata");
1730	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1731		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1732
1733	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1734		return false;
1735
1736	printf("SV[P]PA\tinsert PADDING before\n");
1737	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1738		return die_("creating PADDING block");
1739	padding->length = 0;
1740	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1741		return die_("copying metadata");
1742	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1743		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1744
1745	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1746		return false;
1747
1748	printf("SV[P]PPA\tnext\n");
1749	if(!FLAC__metadata_iterator_next(iterator))
1750		return die_("iterator ended early\n");
1751	our_current_position++;
1752
1753	printf("SVP[P]PA\tnext\n");
1754	if(!FLAC__metadata_iterator_next(iterator))
1755		return die_("iterator ended early\n");
1756	our_current_position++;
1757
1758	printf("SVPP[P]A\tnext\n");
1759	if(!FLAC__metadata_iterator_next(iterator))
1760		return die_("iterator ended early\n");
1761	our_current_position++;
1762
1763	printf("SVPPP[A]\tinsert PADDING after\n");
1764	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1765		return die_("creating PADDING block");
1766	padding->length = 57;
1767	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1768		return die_("copying metadata");
1769	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1770		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1771
1772	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1773		return false;
1774
1775	printf("SVPPPA[P]\tinsert PADDING before\n");
1776	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1777		return die_("creating PADDING block");
1778	padding->length = 99;
1779	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1780		return die_("copying metadata");
1781	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1782		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1783
1784	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1785		return false;
1786
1787	printf("delete iterator\n");
1788	FLAC__metadata_iterator_delete(iterator);
1789	our_current_position = 0;
1790
1791	printf("SVPPPAPP\tmerge padding\n");
1792	FLAC__metadata_chain_merge_padding(chain);
1793	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1794	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
1795	our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
1796	delete_from_our_metadata_(7);
1797	delete_from_our_metadata_(4);
1798	delete_from_our_metadata_(3);
1799
1800	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1801		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1802	if(!compare_chain_(chain, 0, 0))
1803		return false;
1804	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1805		return false;
1806
1807	printf("SVPAP\tsort padding\n");
1808	FLAC__metadata_chain_sort_padding(chain);
1809	our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1810	delete_from_our_metadata_(2);
1811
1812	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1813		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1814	if(!compare_chain_(chain, 0, 0))
1815		return false;
1816	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1817		return false;
1818
1819	printf("create iterator\n");
1820	if(0 == (iterator = FLAC__metadata_iterator_new()))
1821		return die_("allocating memory for iterator");
1822
1823	our_current_position = 0;
1824
1825	FLAC__metadata_iterator_init(iterator, chain);
1826
1827	printf("[S]VAP\tnext\n");
1828	if(!FLAC__metadata_iterator_next(iterator))
1829		return die_("iterator ended early\n");
1830	our_current_position++;
1831
1832	printf("S[V]AP\tnext\n");
1833	if(!FLAC__metadata_iterator_next(iterator))
1834		return die_("iterator ended early\n");
1835	our_current_position++;
1836
1837	printf("SV[A]P\tdelete middle block, replace with padding\n");
1838	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1839		return die_("creating PADDING block");
1840	padding->length = 71;
1841	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1842		return die_("copying object");
1843	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1844		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1845
1846	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1847		return false;
1848
1849	printf("S[V]PP\tnext\n");
1850	if(!FLAC__metadata_iterator_next(iterator))
1851		return die_("iterator ended early\n");
1852	our_current_position++;
1853
1854	printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1855	delete_from_our_metadata_(our_current_position--);
1856	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1857		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1858
1859	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1860		return false;
1861
1862	printf("S[V]P\tnext\n");
1863	if(!FLAC__metadata_iterator_next(iterator))
1864		return die_("iterator ended early\n");
1865	our_current_position++;
1866
1867	printf("SV[P]\tdelete last block, replace with padding\n");
1868	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1869		return die_("creating PADDING block");
1870	padding->length = 219;
1871	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1872		return die_("copying object");
1873	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1874		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1875
1876	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1877		return false;
1878
1879	printf("S[V]P\tnext\n");
1880	if(!FLAC__metadata_iterator_next(iterator))
1881		return die_("iterator ended early\n");
1882	our_current_position++;
1883
1884	printf("SV[P]\tdelete last block, don't replace with padding\n");
1885	delete_from_our_metadata_(our_current_position--);
1886	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1887		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1888
1889	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1890		return false;
1891
1892	printf("S[V]\tprev\n");
1893	if(!FLAC__metadata_iterator_prev(iterator))
1894		return die_("iterator ended early\n");
1895	our_current_position--;
1896
1897	printf("[S]V\tdelete STREAMINFO block, should fail\n");
1898	if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1899		return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
1900
1901	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1902		return false;
1903
1904	printf("delete iterator\n");
1905	FLAC__metadata_iterator_delete(iterator);
1906	our_current_position = 0;
1907
1908	printf("SV\tmerge padding\n");
1909	FLAC__metadata_chain_merge_padding(chain);
1910
1911	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1912		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1913	if(!compare_chain_(chain, 0, 0))
1914		return false;
1915	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1916		return false;
1917
1918	printf("SV\tsort padding\n");
1919	FLAC__metadata_chain_sort_padding(chain);
1920
1921	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1922		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1923	if(!compare_chain_(chain, 0, 0))
1924		return false;
1925	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1926		return false;
1927
1928end:
1929	printf("delete chain\n");
1930
1931	FLAC__metadata_chain_delete(chain);
1932
1933	if(!remove_file_(flacfilename(is_ogg)))
1934		return false;
1935
1936	return true;
1937}
1938
1939static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
1940{
1941	FLAC__Metadata_Iterator *iterator;
1942	FLAC__Metadata_Chain *chain;
1943	FLAC__IOCallbacks callbacks;
1944
1945	memset(&callbacks, 0, sizeof(callbacks));
1946	callbacks.read = (FLAC__IOCallback_Read)fread;
1947#ifdef FLAC__VALGRIND_TESTING
1948	callbacks.write = chain_write_cb_;
1949#else
1950	callbacks.write = (FLAC__IOCallback_Write)fwrite;
1951#endif
1952	callbacks.seek = chain_seek_cb_;
1953	callbacks.tell = chain_tell_cb_;
1954	callbacks.eof = chain_eof_cb_;
1955
1956	printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1957
1958	printf("generate file\n");
1959
1960	if(!generate_file_(/*include_extras=*/false, is_ogg))
1961		return false;
1962
1963	printf("create chain\n");
1964
1965	if(0 == (chain = FLAC__metadata_chain_new()))
1966		return die_("allocating chain");
1967
1968	printf("read chain (filename-based)\n");
1969
1970	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1971		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1972
1973	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
1974	{
1975		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
1976			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1977		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1978			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1979		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1980	}
1981
1982	printf("read chain (filename-based)\n");
1983
1984	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1985		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1986
1987	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
1988	{
1989		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
1990			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1991		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1992			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1993		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1994	}
1995
1996	printf("read chain (callback-based)\n");
1997	{
1998		FILE *file = fopen(flacfilename(is_ogg), "rb");
1999		if(0 == file)
2000			return die_("opening file");
2001		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2002			fclose(file);
2003			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2004		}
2005		fclose(file);
2006	}
2007
2008	printf("write chain with wrong method FLAC__metadata_chain_write()\n");
2009	{
2010		if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
2011			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2012		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2013			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2014		printf("  OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2015	}
2016
2017	printf("read chain (callback-based)\n");
2018	{
2019		FILE *file = fopen(flacfilename(is_ogg), "rb");
2020		if(0 == file)
2021			return die_("opening file");
2022		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2023			fclose(file);
2024			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2025		}
2026		fclose(file);
2027	}
2028
2029	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2030
2031	if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2032		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
2033	else
2034		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
2035
2036	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2037	{
2038		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2039			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2040		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2041			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2042		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2043	}
2044
2045	printf("read chain (callback-based)\n");
2046	{
2047		FILE *file = fopen(flacfilename(is_ogg), "rb");
2048		if(0 == file)
2049			return die_("opening file");
2050		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2051			fclose(file);
2052			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2053		}
2054		fclose(file);
2055	}
2056
2057	printf("create iterator\n");
2058	if(0 == (iterator = FLAC__metadata_iterator_new()))
2059		return die_("allocating memory for iterator");
2060
2061	FLAC__metadata_iterator_init(iterator, chain);
2062
2063	printf("[S]VP\tnext\n");
2064	if(!FLAC__metadata_iterator_next(iterator))
2065		return die_("iterator ended early\n");
2066
2067	printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2068	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
2069		return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
2070
2071	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2072
2073	if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2074		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
2075	else
2076		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
2077
2078	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
2079	{
2080		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
2081			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2082		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2083			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2084		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2085	}
2086
2087	printf("delete iterator\n");
2088
2089	FLAC__metadata_iterator_delete(iterator);
2090
2091	printf("delete chain\n");
2092
2093	FLAC__metadata_chain_delete(chain);
2094
2095	if(!remove_file_(flacfilename(is_ogg)))
2096		return false;
2097
2098	return true;
2099}
2100
2101FLAC__bool test_metadata_file_manipulation(void)
2102{
2103	printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
2104
2105	our_metadata_.num_blocks = 0;
2106
2107	if(!test_level_0_())
2108		return false;
2109
2110	if(!test_level_1_())
2111		return false;
2112
2113	if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2114		return false;
2115	if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2116		return false;
2117	if(!test_level_2_misc_(/*is_ogg=*/false))
2118		return false;
2119
2120	if(FLAC_API_SUPPORTS_OGG_FLAC) {
2121		if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2122			return false;
2123		if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2124			return false;
2125#if 0
2126		/* when ogg flac write is supported, will have to add this: */
2127		if(!test_level_2_misc_(/*is_ogg=*/true))
2128			return false;
2129#endif
2130	}
2131
2132	return true;
2133}
2134