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