xref: /aosp_15_r20/external/flac/src/test_libFLAC/metadata_manip.c (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1 /* test_libFLAC - Unit tester for libFLAC
2  * Copyright (C) 2002-2009  Josh Coalson
3  * Copyright (C) 2011-2023  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) && !defined(_WIN32)
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 	if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
911 		return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
912 
913 	printf("[S]VP\tnext\n");
914 	if(!FLAC__metadata_simple_iterator_next(iterator))
915 		return die_("iterator ended early\n");
916 	our_current_position++;
917 
918 	printf("S[V]P\tnext\n");
919 	if(!FLAC__metadata_simple_iterator_next(iterator))
920 		return die_("iterator ended early\n");
921 	our_current_position++;
922 
923 	printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
924 	padding->length = 25;
925 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
926 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
927 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
928 		return false;
929 
930 	printf("SVP[P]\tprev\n");
931 	if(!FLAC__metadata_simple_iterator_prev(iterator))
932 		return die_("iterator ended early\n");
933 	our_current_position--;
934 
935 	printf("SV[P]P\tprev\n");
936 	if(!FLAC__metadata_simple_iterator_prev(iterator))
937 		return die_("iterator ended early\n");
938 	our_current_position--;
939 
940 	printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
941 	padding->length = 30;
942 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
943 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
944 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
945 		return false;
946 
947 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
948 		return false;
949 
950 	printf("SV[P]PP\tprev\n");
951 	if(!FLAC__metadata_simple_iterator_prev(iterator))
952 		return die_("iterator ended early\n");
953 	our_current_position--;
954 
955 	printf("S[V]PPP\tprev\n");
956 	if(!FLAC__metadata_simple_iterator_prev(iterator))
957 		return die_("iterator ended early\n");
958 	our_current_position--;
959 
960 	printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
961 	if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
962 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
963 
964 	if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
965 		return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
966 
967 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
968 		return false;
969 
970 	printf("[S]VPPP\tnext\n");
971 	if(!FLAC__metadata_simple_iterator_next(iterator))
972 		return die_("iterator ended early\n");
973 	our_current_position++;
974 
975 	printf("S[V]PPP\tnext\n");
976 	if(!FLAC__metadata_simple_iterator_next(iterator))
977 		return die_("iterator ended early\n");
978 	our_current_position++;
979 
980 	printf("SV[P]PP\tdelete (middle block), replace with padding\n");
981 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
982 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
983 	our_current_position--;
984 
985 	printf("S[V]PPP\tnext\n");
986 	if(!FLAC__metadata_simple_iterator_next(iterator))
987 		return die_("iterator ended early\n");
988 	our_current_position++;
989 
990 	printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
991 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
992 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
993 	delete_from_our_metadata_(our_current_position--);
994 
995 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
996 		return false;
997 
998 	printf("S[V]PP\tnext\n");
999 	if(!FLAC__metadata_simple_iterator_next(iterator))
1000 		return die_("iterator ended early\n");
1001 	our_current_position++;
1002 
1003 	printf("SV[P]P\tnext\n");
1004 	if(!FLAC__metadata_simple_iterator_next(iterator))
1005 		return die_("iterator ended early\n");
1006 	our_current_position++;
1007 
1008 	printf("SVP[P]\tdelete (last block), replace with padding\n");
1009 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
1010 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1011 	our_current_position--;
1012 
1013 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1014 		return false;
1015 
1016 	printf("SV[P]P\tnext\n");
1017 	if(!FLAC__metadata_simple_iterator_next(iterator))
1018 		return die_("iterator ended early\n");
1019 	our_current_position++;
1020 
1021 	printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1022 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1023 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1024 	delete_from_our_metadata_(our_current_position--);
1025 
1026 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1027 		return false;
1028 
1029 	printf("SV[P]\tprev\n");
1030 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1031 		return die_("iterator ended early\n");
1032 	our_current_position--;
1033 
1034 	printf("S[V]P\tprev\n");
1035 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1036 		return die_("iterator ended early\n");
1037 	our_current_position--;
1038 
1039 	printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1040 	FLAC__ASSERT(our_current_position == 0);
1041 	block = FLAC__metadata_simple_iterator_get_block(iterator);
1042 	block->data.stream_info.sample_rate = 32000;
1043 	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1044 		return die_("copying object");
1045 	if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
1046 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
1047 	FLAC__metadata_object_delete(block);
1048 
1049 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1050 		return false;
1051 
1052 	printf("[S]VP\tnext\n");
1053 	if(!FLAC__metadata_simple_iterator_next(iterator))
1054 		return die_("iterator ended early\n");
1055 	our_current_position++;
1056 
1057 	printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1058 	app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
1059 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1060 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1061 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1062 		return false;
1063 	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1064 
1065 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1066 		return false;
1067 
1068 	printf("SV[A]P\tnext\n");
1069 	if(!FLAC__metadata_simple_iterator_next(iterator))
1070 		return die_("iterator ended early\n");
1071 	our_current_position++;
1072 
1073 	printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1074 	app->data.application.id[0] = 'f'; /* twiddle the id */
1075 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1076 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1077 	if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1078 		return false;
1079 	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1080 
1081 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1082 		return false;
1083 
1084 	printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1085 	app->data.application.id[0] = 'g'; /* twiddle the id */
1086 	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1087 		return die_("setting APPLICATION data");
1088 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1089 		return die_("copying object");
1090 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1091 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1092 
1093 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1094 		return false;
1095 
1096 	printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1097 	app->data.application.id[0] = 'h'; /* twiddle the id */
1098 	if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
1099 		return die_("setting APPLICATION data");
1100 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1101 		return die_("copying object");
1102 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1103 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1104 
1105 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1106 		return false;
1107 
1108 	printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1109 	app->data.application.id[0] = 'i'; /* twiddle the id */
1110 	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1111 		return die_("setting APPLICATION data");
1112 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1113 		return die_("copying object");
1114 	our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
1115 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1116 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1117 
1118 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1119 		return false;
1120 
1121 	printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1122 	app->data.application.id[0] = 'j'; /* twiddle the id */
1123 	if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
1124 		return die_("setting APPLICATION data");
1125 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1126 		return die_("copying object");
1127 	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1128 		return die_("copying object");
1129 	our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
1130 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1131 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1132 
1133 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1134 		return false;
1135 
1136 	printf("SVA[A]PP\tnext\n");
1137 	if(!FLAC__metadata_simple_iterator_next(iterator))
1138 		return die_("iterator ended early\n");
1139 	our_current_position++;
1140 
1141 	printf("SVAA[P]P\tnext\n");
1142 	if(!FLAC__metadata_simple_iterator_next(iterator))
1143 		return die_("iterator ended early\n");
1144 	our_current_position++;
1145 
1146 	printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1147 	padding->length = 5;
1148 	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1149 		return die_("copying object");
1150 	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1151 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1152 
1153 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1154 		return false;
1155 
1156 	printf("SVAAP[P]\tset APPLICATION (grow)\n");
1157 	app->data.application.id[0] = 'k'; /* twiddle the id */
1158 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1159 		return die_("copying object");
1160 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1161 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1162 
1163 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1164 		return false;
1165 
1166 	printf("SVAAP[A]\tset PADDING (equal)\n");
1167 	padding->length = 27;
1168 	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1169 		return die_("copying object");
1170 	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1171 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1172 
1173 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1174 		return false;
1175 
1176 	printf("SVAAP[P]\tprev\n");
1177 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1178 		return die_("iterator ended early\n");
1179 	our_current_position--;
1180 
1181 	printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1182 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1183 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1184 	delete_from_our_metadata_(our_current_position--);
1185 
1186 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1187 		return false;
1188 
1189 	printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1190 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1191 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1192 	delete_from_our_metadata_(our_current_position--);
1193 
1194 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1195 		return false;
1196 
1197 	printf("SV[A]P\tnext\n");
1198 	if(!FLAC__metadata_simple_iterator_next(iterator))
1199 		return die_("iterator ended early\n");
1200 	our_current_position++;
1201 
1202 	printf("SVA[P]\tinsert PADDING after\n");
1203 	padding->length = 5;
1204 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1205 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1206 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1207 		return false;
1208 
1209 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1210 		return false;
1211 
1212 	printf("SVAP[P]\tprev\n");
1213 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1214 		return die_("iterator ended early\n");
1215 	our_current_position--;
1216 
1217 	printf("SVA[P]P\tprev\n");
1218 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1219 		return die_("iterator ended early\n");
1220 	our_current_position--;
1221 
1222 	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1223 	if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
1224 		return die_("setting APPLICATION data");
1225 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1226 		return die_("copying object");
1227 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1228 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1229 
1230 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1231 		return false;
1232 
1233 	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1234 	if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
1235 		return die_("setting APPLICATION data");
1236 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1237 		return die_("copying object");
1238 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1239 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1240 
1241 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1242 		return false;
1243 
1244 	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1245 	if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
1246 		return die_("setting APPLICATION data");
1247 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1248 		return die_("copying object");
1249 	our_metadata_.blocks[our_current_position+1]->length = 0;
1250 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1251 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1252 
1253 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1254 		return false;
1255 
1256 	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1257 	if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
1258 		return die_("setting APPLICATION data");
1259 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1260 		return die_("copying object");
1261 	delete_from_our_metadata_(our_current_position+1);
1262 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1263 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1264 
1265 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1266 		return false;
1267 
1268 	printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1269 	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1270 		return die_("setting APPLICATION data");
1271 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1272 		return die_("copying object");
1273 	delete_from_our_metadata_(our_current_position+1);
1274 	our_metadata_.blocks[our_current_position]->is_last = true;
1275 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1276 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1277 
1278 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1279 		return false;
1280 
1281 	printf("SV[A]\tset PADDING (equal size)\n");
1282 	padding->length = app->length;
1283 	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1284 		return die_("copying object");
1285 	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
1286 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
1287 
1288 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1289 		return false;
1290 
1291 	printf("SV[P]\tinsert PADDING after\n");
1292 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1293 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1294 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1295 		return false;
1296 
1297 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1298 		return false;
1299 
1300 	printf("SVP[P]\tinsert PADDING after\n");
1301 	padding->length = 5;
1302 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1303 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1304 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1305 		return false;
1306 
1307 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1308 		return false;
1309 
1310 	printf("SVPP[P]\tprev\n");
1311 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1312 		return die_("iterator ended early\n");
1313 	our_current_position--;
1314 
1315 	printf("SVP[P]P\tprev\n");
1316 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1317 		return die_("iterator ended early\n");
1318 	our_current_position--;
1319 
1320 	printf("SV[P]PP\tprev\n");
1321 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1322 		return die_("iterator ended early\n");
1323 	our_current_position--;
1324 
1325 	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1326 	if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1327 		return die_("setting APPLICATION data");
1328 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1329 		return die_("copying object");
1330 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1331 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1332 
1333 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1334 		return false;
1335 
1336 	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1337 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1338 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1339 	delete_from_our_metadata_(our_current_position--);
1340 
1341 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1342 		return false;
1343 
1344 	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1345 	if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1346 		return die_("setting APPLICATION data");
1347 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1348 		return die_("copying object");
1349 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1350 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1351 
1352 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1353 		return false;
1354 
1355 	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1356 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1357 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1358 	delete_from_our_metadata_(our_current_position--);
1359 
1360 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1361 		return false;
1362 
1363 	printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1364 	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1365 		return die_("setting APPLICATION data");
1366 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1367 		return die_("copying object");
1368 	delete_from_our_metadata_(our_current_position+1);
1369 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1370 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1371 
1372 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1373 		return false;
1374 
1375 	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1376 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1377 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1378 	delete_from_our_metadata_(our_current_position--);
1379 
1380 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1381 		return false;
1382 
1383 	printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1384 	if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1385 		return die_("setting APPLICATION data");
1386 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1387 		return die_("copying object");
1388 	our_metadata_.blocks[our_current_position+1]->length = 0;
1389 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1390 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1391 
1392 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1393 		return false;
1394 
1395 	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1396 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1397 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1398 	delete_from_our_metadata_(our_current_position--);
1399 
1400 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1401 		return false;
1402 
1403 	printf("S[V]PP\tnext\n");
1404 	if(!FLAC__metadata_simple_iterator_next(iterator))
1405 		return die_("iterator ended early\n");
1406 	our_current_position++;
1407 
1408 	printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1409 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1410 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1411 	delete_from_our_metadata_(our_current_position--);
1412 
1413 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1414 		return false;
1415 
1416 	printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1417 	if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1418 		return die_("setting APPLICATION data");
1419 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1420 		return die_("copying object");
1421 	delete_from_our_metadata_(our_current_position+1);
1422 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1423 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1424 
1425 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1426 		return false;
1427 
1428 	printf("delete simple iterator\n");
1429 
1430 	FLAC__metadata_simple_iterator_delete(iterator);
1431 
1432 	FLAC__metadata_object_delete(app);
1433 	FLAC__metadata_object_delete(padding);
1434 
1435 	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1436 		return false;
1437 
1438 	return true;
1439 }
1440 
test_level_2_(FLAC__bool filename_based,FLAC__bool is_ogg)1441 static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
1442 {
1443 	FLAC__Metadata_Iterator *iterator;
1444 	FLAC__Metadata_Chain *chain;
1445 	FLAC__StreamMetadata *block, *app, *padding;
1446 	FLAC__byte data[2000];
1447 	uint32_t our_current_position;
1448 
1449 	/* initialize 'data' to avoid Valgrind errors */
1450 	memset(data, 0, sizeof(data));
1451 
1452 	printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1453 
1454 	printf("generate read-only file\n");
1455 
1456 	if(!generate_file_(/*include_extras=*/false, is_ogg))
1457 		return false;
1458 
1459 	if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1460 		return false;
1461 
1462 	printf("create chain\n");
1463 
1464 	if(0 == (chain = FLAC__metadata_chain_new()))
1465 		return die_("allocating chain");
1466 
1467 	printf("read chain\n");
1468 
1469 	if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1470 		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1471 
1472 	printf("[S]VP\ttest initial metadata\n");
1473 
1474 	if(!compare_chain_(chain, 0, 0))
1475 		return false;
1476 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1477 		return false;
1478 
1479 	if(is_ogg)
1480 		goto end;
1481 
1482 	printf("switch file to read-write\n");
1483 
1484 	if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1485 		return false;
1486 
1487 	printf("create iterator\n");
1488 	if(0 == (iterator = FLAC__metadata_iterator_new()))
1489 		return die_("allocating memory for iterator");
1490 
1491 	our_current_position = 0;
1492 
1493 	FLAC__metadata_iterator_init(iterator, chain);
1494 
1495 	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1496 		return die_("getting block from iterator");
1497 
1498 	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1499 
1500 	printf("[S]VP\tmodify STREAMINFO, write\n");
1501 
1502 	block->data.stream_info.sample_rate = 32000;
1503 	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1504 		return die_("copying object");
1505 
1506 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1507 		return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1508 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1509 		return false;
1510 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1511 		return false;
1512 
1513 	printf("[S]VP\tnext\n");
1514 	if(!FLAC__metadata_iterator_next(iterator))
1515 		return die_("iterator ended early\n");
1516 	our_current_position++;
1517 
1518 	printf("S[V]P\tnext\n");
1519 	if(!FLAC__metadata_iterator_next(iterator))
1520 		return die_("iterator ended early\n");
1521 	our_current_position++;
1522 
1523 	printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1524 	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1525 		return die_("getting block from iterator");
1526 	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1527 		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1528 	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1529 	if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1530 		return die_("setting APPLICATION data");
1531 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1532 		return die_("copying object");
1533 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1534 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1535 
1536 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1537 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1538 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1539 		return false;
1540 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1541 		return false;
1542 
1543 	printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1544 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1545 		return die_("copying object");
1546 	if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1547 		return die_("setting APPLICATION data");
1548 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1549 		return die_("copying object");
1550 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1551 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1552 
1553 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1554 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1555 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1556 		return false;
1557 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1558 		return false;
1559 
1560 	printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1561 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1562 		return die_("copying object");
1563 	if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1564 		return die_("setting APPLICATION data");
1565 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1566 		return die_("copying object");
1567 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1568 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1569 
1570 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1571 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1572 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1573 		return false;
1574 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1575 		return false;
1576 
1577 	printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1578 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1579 		return die_("copying object");
1580 	if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1581 		return die_("setting APPLICATION data");
1582 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1583 		return die_("copying object");
1584 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1585 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1586 
1587 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1588 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1589 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1590 		return false;
1591 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1592 		return false;
1593 
1594 	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1595 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1596 		return die_("copying object");
1597 	if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1598 		return die_("setting APPLICATION data");
1599 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1600 		return die_("copying object");
1601 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1602 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1603 
1604 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1605 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1606 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1607 		return false;
1608 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1609 		return false;
1610 
1611 	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1612 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1613 		return die_("creating PADDING block");
1614 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1615 		return die_("copying object");
1616 	if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1617 		return die_("setting APPLICATION data");
1618 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1619 		return die_("copying object");
1620 	padding->length = 0;
1621 	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1622 		return die_("internal error");
1623 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1624 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1625 
1626 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1627 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1628 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1629 		return false;
1630 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1631 		return false;
1632 
1633 	printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1634 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1635 		return die_("copying object");
1636 	if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1637 		return die_("setting APPLICATION data");
1638 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1639 		return die_("copying object");
1640 	our_metadata_.blocks[our_current_position+1]->length = 13;
1641 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1642 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1643 
1644 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1645 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1646 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1647 		return false;
1648 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1649 		return false;
1650 
1651 	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1652 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1653 		return die_("copying object");
1654 	if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1655 		return die_("setting APPLICATION data");
1656 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1657 		return die_("copying object");
1658 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1659 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1660 
1661 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1662 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1663 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1664 		return false;
1665 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1666 		return false;
1667 
1668 	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1669 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1670 		return die_("copying object");
1671 	if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1672 		return die_("setting APPLICATION data");
1673 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1674 		return die_("copying object");
1675 	our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1676 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1677 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1678 
1679 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1680 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1681 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1682 		return false;
1683 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1684 		return false;
1685 
1686 	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1687 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1688 		return die_("copying object");
1689 	if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1690 		return die_("setting APPLICATION data");
1691 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1692 		return die_("copying object");
1693 	delete_from_our_metadata_(our_current_position+1);
1694 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1695 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1696 
1697 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1698 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1699 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1700 		return false;
1701 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1702 		return false;
1703 
1704 	printf("SV[A]\tprev\n");
1705 	if(!FLAC__metadata_iterator_prev(iterator))
1706 		return die_("iterator ended early\n");
1707 	our_current_position--;
1708 
1709 	printf("S[V]A\tprev\n");
1710 	if(!FLAC__metadata_iterator_prev(iterator))
1711 		return die_("iterator ended early\n");
1712 	our_current_position--;
1713 
1714 	printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1715 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1716 		return die_("creating PADDING block");
1717 	padding->length = 30;
1718 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1719 		printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1720 	else
1721 		return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1722 
1723 	printf("[S]VP\tnext\n");
1724 	if(!FLAC__metadata_iterator_next(iterator))
1725 		return die_("iterator ended early\n");
1726 	our_current_position++;
1727 
1728 	printf("S[V]A\tinsert PADDING after\n");
1729 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1730 		return die_("copying metadata");
1731 	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1732 		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1733 
1734 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1735 		return false;
1736 
1737 	printf("SV[P]A\tinsert PADDING before\n");
1738 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1739 		return die_("creating PADDING block");
1740 	padding->length = 17;
1741 	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1742 		return die_("copying metadata");
1743 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1744 		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1745 
1746 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1747 		return false;
1748 
1749 	printf("SV[P]PA\tinsert PADDING before\n");
1750 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1751 		return die_("creating PADDING block");
1752 	padding->length = 0;
1753 	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1754 		return die_("copying metadata");
1755 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1756 		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1757 
1758 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1759 		return false;
1760 
1761 	printf("SV[P]PPA\tnext\n");
1762 	if(!FLAC__metadata_iterator_next(iterator))
1763 		return die_("iterator ended early\n");
1764 	our_current_position++;
1765 
1766 	printf("SVP[P]PA\tnext\n");
1767 	if(!FLAC__metadata_iterator_next(iterator))
1768 		return die_("iterator ended early\n");
1769 	our_current_position++;
1770 
1771 	printf("SVPP[P]A\tnext\n");
1772 	if(!FLAC__metadata_iterator_next(iterator))
1773 		return die_("iterator ended early\n");
1774 	our_current_position++;
1775 
1776 	printf("SVPPP[A]\tinsert PADDING after\n");
1777 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1778 		return die_("creating PADDING block");
1779 	padding->length = 57;
1780 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1781 		return die_("copying metadata");
1782 	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1783 		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1784 
1785 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1786 		return false;
1787 
1788 	printf("SVPPPA[P]\tinsert PADDING before\n");
1789 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1790 		return die_("creating PADDING block");
1791 	padding->length = 99;
1792 	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1793 		return die_("copying metadata");
1794 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1795 		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1796 
1797 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1798 		return false;
1799 
1800 	printf("delete iterator\n");
1801 	FLAC__metadata_iterator_delete(iterator);
1802 	our_current_position = 0;
1803 
1804 	printf("SVPPPAPP\tmerge padding\n");
1805 	FLAC__metadata_chain_merge_padding(chain);
1806 	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1807 	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
1808 	our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
1809 	delete_from_our_metadata_(7);
1810 	delete_from_our_metadata_(4);
1811 	delete_from_our_metadata_(3);
1812 
1813 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1814 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1815 	if(!compare_chain_(chain, 0, 0))
1816 		return false;
1817 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1818 		return false;
1819 
1820 	printf("SVPAP\tsort padding\n");
1821 	FLAC__metadata_chain_sort_padding(chain);
1822 	our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1823 	delete_from_our_metadata_(2);
1824 
1825 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1826 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1827 	if(!compare_chain_(chain, 0, 0))
1828 		return false;
1829 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1830 		return false;
1831 
1832 	printf("create iterator\n");
1833 	if(0 == (iterator = FLAC__metadata_iterator_new()))
1834 		return die_("allocating memory for iterator");
1835 
1836 	our_current_position = 0;
1837 
1838 	FLAC__metadata_iterator_init(iterator, chain);
1839 
1840 	printf("[S]VAP\tnext\n");
1841 	if(!FLAC__metadata_iterator_next(iterator))
1842 		return die_("iterator ended early\n");
1843 	our_current_position++;
1844 
1845 	printf("S[V]AP\tnext\n");
1846 	if(!FLAC__metadata_iterator_next(iterator))
1847 		return die_("iterator ended early\n");
1848 	our_current_position++;
1849 
1850 	printf("SV[A]P\tdelete middle block, replace with padding\n");
1851 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1852 		return die_("creating PADDING block");
1853 	padding->length = 71;
1854 	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1855 		return die_("copying object");
1856 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1857 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1858 
1859 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1860 		return false;
1861 
1862 	printf("S[V]PP\tnext\n");
1863 	if(!FLAC__metadata_iterator_next(iterator))
1864 		return die_("iterator ended early\n");
1865 	our_current_position++;
1866 
1867 	printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1868 	delete_from_our_metadata_(our_current_position--);
1869 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1870 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1871 
1872 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1873 		return false;
1874 
1875 	printf("S[V]P\tnext\n");
1876 	if(!FLAC__metadata_iterator_next(iterator))
1877 		return die_("iterator ended early\n");
1878 	our_current_position++;
1879 
1880 	printf("SV[P]\tdelete last block, replace with padding\n");
1881 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1882 		return die_("creating PADDING block");
1883 	padding->length = 219;
1884 	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1885 		return die_("copying object");
1886 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1887 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1888 
1889 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1890 		return false;
1891 
1892 	printf("S[V]P\tnext\n");
1893 	if(!FLAC__metadata_iterator_next(iterator))
1894 		return die_("iterator ended early\n");
1895 	our_current_position++;
1896 
1897 	printf("SV[P]\tdelete last block, don't replace with padding\n");
1898 	delete_from_our_metadata_(our_current_position--);
1899 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1900 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1901 
1902 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1903 		return false;
1904 
1905 	printf("S[V]\tprev\n");
1906 	if(!FLAC__metadata_iterator_prev(iterator))
1907 		return die_("iterator ended early\n");
1908 	our_current_position--;
1909 
1910 	printf("[S]V\tdelete STREAMINFO block, should fail\n");
1911 	if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1912 		return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
1913 
1914 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1915 		return false;
1916 
1917 	printf("delete iterator\n");
1918 	FLAC__metadata_iterator_delete(iterator);
1919 	our_current_position = 0;
1920 
1921 	printf("SV\tmerge padding\n");
1922 	FLAC__metadata_chain_merge_padding(chain);
1923 
1924 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1925 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1926 	if(!compare_chain_(chain, 0, 0))
1927 		return false;
1928 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1929 		return false;
1930 
1931 	printf("SV\tsort padding\n");
1932 	FLAC__metadata_chain_sort_padding(chain);
1933 
1934 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1935 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1936 	if(!compare_chain_(chain, 0, 0))
1937 		return false;
1938 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1939 		return false;
1940 
1941 end:
1942 	printf("delete chain\n");
1943 
1944 	FLAC__metadata_chain_delete(chain);
1945 
1946 	if(!remove_file_(flacfilename(is_ogg)))
1947 		return false;
1948 
1949 	return true;
1950 }
1951 
test_level_2_misc_(FLAC__bool is_ogg)1952 static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
1953 {
1954 	FLAC__Metadata_Iterator *iterator;
1955 	FLAC__Metadata_Chain *chain;
1956 	FLAC__IOCallbacks callbacks;
1957 
1958 	memset(&callbacks, 0, sizeof(callbacks));
1959 	callbacks.read = (FLAC__IOCallback_Read)fread;
1960 #ifdef FLAC__VALGRIND_TESTING
1961 	callbacks.write = chain_write_cb_;
1962 #else
1963 	callbacks.write = (FLAC__IOCallback_Write)fwrite;
1964 #endif
1965 	callbacks.seek = chain_seek_cb_;
1966 	callbacks.tell = chain_tell_cb_;
1967 	callbacks.eof = chain_eof_cb_;
1968 
1969 	printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1970 
1971 	printf("generate file\n");
1972 
1973 	if(!generate_file_(/*include_extras=*/false, is_ogg))
1974 		return false;
1975 
1976 	printf("create chain\n");
1977 
1978 	if(0 == (chain = FLAC__metadata_chain_new()))
1979 		return die_("allocating chain");
1980 
1981 	printf("read chain (filename-based)\n");
1982 
1983 	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1984 		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1985 
1986 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
1987 	{
1988 		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
1989 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1990 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1991 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1992 		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1993 	}
1994 
1995 	printf("read chain (filename-based)\n");
1996 
1997 	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1998 		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1999 
2000 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2001 	{
2002 		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2003 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2004 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2005 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2006 		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2007 	}
2008 
2009 	printf("read chain (callback-based)\n");
2010 	{
2011 		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2012 		if(0 == file)
2013 			return die_("opening file");
2014 		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2015 			fclose(file);
2016 			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2017 		}
2018 		fclose(file);
2019 	}
2020 
2021 	printf("write chain with wrong method FLAC__metadata_chain_write()\n");
2022 	{
2023 		if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
2024 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2025 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2026 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2027 		printf("  OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2028 	}
2029 
2030 	printf("read chain (callback-based)\n");
2031 	{
2032 		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2033 		if(0 == file)
2034 			return die_("opening file");
2035 		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2036 			fclose(file);
2037 			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2038 		}
2039 		fclose(file);
2040 	}
2041 
2042 	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2043 
2044 	if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2045 		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
2046 	else
2047 		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
2048 
2049 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2050 	{
2051 		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2052 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2053 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2054 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2055 		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2056 	}
2057 
2058 	printf("read chain (callback-based)\n");
2059 	{
2060 		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2061 		if(0 == file)
2062 			return die_("opening file");
2063 		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2064 			fclose(file);
2065 			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2066 		}
2067 		fclose(file);
2068 	}
2069 
2070 	printf("create iterator\n");
2071 	if(0 == (iterator = FLAC__metadata_iterator_new()))
2072 		return die_("allocating memory for iterator");
2073 
2074 	FLAC__metadata_iterator_init(iterator, chain);
2075 
2076 	printf("[S]VP\tnext\n");
2077 	if(!FLAC__metadata_iterator_next(iterator))
2078 		return die_("iterator ended early\n");
2079 
2080 	printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2081 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
2082 		return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
2083 
2084 	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2085 
2086 	if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2087 		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
2088 	else
2089 		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
2090 
2091 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
2092 	{
2093 		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
2094 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2095 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2096 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2097 		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2098 	}
2099 
2100 	printf("delete iterator\n");
2101 
2102 	FLAC__metadata_iterator_delete(iterator);
2103 
2104 	printf("delete chain\n");
2105 
2106 	FLAC__metadata_chain_delete(chain);
2107 
2108 	if(!remove_file_(flacfilename(is_ogg)))
2109 		return false;
2110 
2111 	return true;
2112 }
2113 
test_metadata_file_manipulation(void)2114 FLAC__bool test_metadata_file_manipulation(void)
2115 {
2116 	printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
2117 
2118 	our_metadata_.num_blocks = 0;
2119 
2120 	if(!test_level_0_())
2121 		return false;
2122 
2123 	if(!test_level_1_())
2124 		return false;
2125 
2126 	if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2127 		return false;
2128 	if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2129 		return false;
2130 	if(!test_level_2_misc_(/*is_ogg=*/false))
2131 		return false;
2132 
2133 	if(FLAC_API_SUPPORTS_OGG_FLAC) {
2134 		if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2135 			return false;
2136 		if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2137 			return false;
2138 #if 0
2139 		/* when ogg flac write is supported, will have to add this: */
2140 		if(!test_level_2_misc_(/*is_ogg=*/true))
2141 			return false;
2142 #endif
2143 	}
2144 
2145 	return true;
2146 }
2147