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