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