1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <stdlib.h> /* for malloc() */
25 #include <string.h> /* for memcpy()/memset() */
26 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
27 #include <utime.h> /* for utime() */
28 #include <unistd.h> /* for chown(), unlink() */
29 #include <sys/stat.h> /* for stat(), maybe chmod() */
30 #include "FLAC/assert.h"
31 #include "FLAC++/decoder.h"
32 #include "FLAC++/metadata.h"
33 #include "share/grabbag.h"
34 #include "share/compat.h"
36 #include "test_libs_common/file_utils_flac.h"
39 /******************************************************************************
40 The general strategy of these tests (for interface levels 1 and 2) is
41 to create a dummy FLAC file with a known set of initial metadata
42 blocks, then keep a mirror locally of what we expect the metadata to be
43 after each operation. Then testing becomes a simple matter of running
44 a FLAC::Decoder::File over the dummy file after each operation, comparing
45 the decoded metadata to what's in our local copy. If there are any
46 differences in the metadata, or the actual audio data is corrupted, we
47 will catch it while decoding.
48 ******************************************************************************/
50 class OurFileDecoder: public FLAC::Decoder::File {
52 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
54 bool ignore_metadata_;
57 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
58 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
59 void error_callback(::FLAC__StreamDecoderErrorStatus status);
63 FLAC::Metadata::Prototype *blocks[64];
67 /* our copy of the metadata in flacfilename() */
68 static OurMetadata our_metadata_;
70 /* the current block number that corresponds to the position of the iterator we are testing */
71 static unsigned mc_our_block_number_ = 0;
73 static const char *flacfilename(bool is_ogg)
75 return is_ogg? "metadata.oga" : "metadata.flac";
78 static bool die_(const char *msg)
80 printf("ERROR: %s\n", msg);
84 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
86 printf("ERROR: %s\n", msg);
87 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
91 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
93 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
94 printf("ERROR: %s\n", msg);
95 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
99 static void *malloc_or_die_(size_t size)
101 void *x = malloc(size);
103 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
109 static char *strdup_or_die_(const char *s)
113 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
119 /* functions for working with our metadata copy */
121 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
124 FLAC::Metadata::Prototype *obj = block;
125 FLAC__ASSERT(position < our_metadata_.num_blocks);
127 if(0 == (obj = FLAC::Metadata::clone(block)))
128 return die_("during FLAC::Metadata::clone()");
130 delete our_metadata_.blocks[position];
131 our_metadata_.blocks[position] = obj;
133 /* set the is_last flags */
134 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
135 our_metadata_.blocks[i]->set_is_last(false);
136 our_metadata_.blocks[i]->set_is_last(true);
141 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
144 FLAC::Metadata::Prototype *obj = block;
146 if(0 == (obj = FLAC::Metadata::clone(block)))
147 return die_("during FLAC::Metadata::clone()");
149 if(position > our_metadata_.num_blocks) {
150 position = our_metadata_.num_blocks;
153 for(i = our_metadata_.num_blocks; i > position; i--)
154 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
156 our_metadata_.blocks[position] = obj;
157 our_metadata_.num_blocks++;
159 /* set the is_last flags */
160 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
161 our_metadata_.blocks[i]->set_is_last(false);
162 our_metadata_.blocks[i]->set_is_last(true);
167 static void delete_from_our_metadata_(unsigned position)
170 FLAC__ASSERT(position < our_metadata_.num_blocks);
171 delete our_metadata_.blocks[position];
172 for(i = position; i < our_metadata_.num_blocks - 1; i++)
173 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
174 our_metadata_.num_blocks--;
176 /* set the is_last flags */
177 if(our_metadata_.num_blocks > 0) {
178 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
179 our_metadata_.blocks[i]->set_is_last(false);
180 our_metadata_.blocks[i]->set_is_last(true);
184 void add_to_padding_length_(unsigned index, int delta)
186 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
187 FLAC__ASSERT(0 != padding);
188 padding->set_length((unsigned)((int)padding->get_length() + delta));
192 * This wad of functions supports filename- and callback-based chain reading/writing.
193 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
195 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
197 static const char *tempfile_suffix = ".metadata_edit";
199 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
201 strcpy(*tempfilename, filename);
202 strcat(*tempfilename, tempfile_suffix);
204 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
210 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
213 (void)fclose(*tempfile);
217 if(0 != *tempfilename) {
218 (void)unlink(*tempfilename);
224 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
226 FLAC__ASSERT(0 != filename);
227 FLAC__ASSERT(0 != tempfile);
228 FLAC__ASSERT(0 != tempfilename);
229 FLAC__ASSERT(0 != *tempfilename);
232 (void)fclose(*tempfile);
236 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
237 /* on some flavors of windows, rename() will fail if the destination already exists */
238 if(unlink(filename) < 0) {
239 cleanup_tempfile_(tempfile, tempfilename);
244 if(0 != rename(*tempfilename, filename)) {
245 cleanup_tempfile_(tempfile, tempfilename);
249 cleanup_tempfile_(tempfile, tempfilename);
254 bool get_file_stats_(const char *filename, struct stat *stats)
256 FLAC__ASSERT(0 != filename);
257 FLAC__ASSERT(0 != stats);
258 return (0 == stat(filename, stats));
261 void set_file_stats_(const char *filename, struct stat *stats)
263 struct utimbuf srctime;
265 FLAC__ASSERT(0 != filename);
266 FLAC__ASSERT(0 != stats);
268 srctime.actime = stats->st_atime;
269 srctime.modtime = stats->st_mtime;
270 (void)chmod(filename, stats->st_mode);
271 (void)utime(filename, &srctime);
272 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
273 (void)chown(filename, stats->st_uid, (gid_t)(-1));
274 (void)chown(filename, (uid_t)(-1), stats->st_gid);
278 #ifdef FLAC__VALGRIND_TESTING
279 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
281 FILE *stream = (FILE*)handle;
282 size_t ret = fwrite(ptr, size, nmemb, stream);
289 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
291 off_t o = (off_t)offset;
292 FLAC__ASSERT(offset == o);
293 return fseeko((FILE*)handle, o, whence);
296 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
298 return ftello((FILE*)handle);
301 static int chain_eof_cb_(::FLAC__IOHandle handle)
303 return feof((FILE*)handle);
306 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
309 return chain.write(use_padding, preserve_file_stats);
311 ::FLAC__IOCallbacks callbacks;
313 memset(&callbacks, 0, sizeof(callbacks));
314 callbacks.read = (::FLAC__IOCallback_Read)fread;
315 #ifdef FLAC__VALGRIND_TESTING
316 callbacks.write = chain_write_cb_;
318 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
320 callbacks.seek = chain_seek_cb_;
321 callbacks.eof = chain_eof_cb_;
323 if(chain.check_if_tempfile_needed(use_padding)) {
325 FILE *file, *tempfile;
327 if(preserve_file_stats) {
328 if(!get_file_stats_(filename, &stats))
331 if(0 == (file = fopen(filename, "rb")))
332 return false; /*@@@@ chain status still says OK though */
333 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
335 cleanup_tempfile_(&tempfile, &tempfilename);
336 return false; /*@@@@ chain status still says OK though */
338 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
346 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
348 if(preserve_file_stats)
349 set_file_stats_(filename, &stats);
352 FILE *file = fopen(filename, "r+b");
354 return false; /*@@@@ chain status still says OK though */
355 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks)) {
366 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg)
369 return chain.read(filename, is_ogg);
371 ::FLAC__IOCallbacks callbacks;
373 memset(&callbacks, 0, sizeof(callbacks));
374 callbacks.read = (::FLAC__IOCallback_Read)fread;
375 callbacks.seek = chain_seek_cb_;
376 callbacks.tell = chain_tell_cb_;
380 FILE *file = fopen(filename, "rb");
382 return false; /*@@@@ chain status still says OK though */
383 ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg);
390 /* function for comparing our metadata to a FLAC::Metadata::Chain */
392 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
395 FLAC::Metadata::Iterator iterator;
398 printf("\tcomparing chain... ");
401 if(!iterator.is_valid())
402 return die_("allocating memory for iterator");
404 iterator.init(chain);
408 FLAC::Metadata::Prototype *block;
413 if(0 == (block = iterator.get_block()))
414 return die_("getting block from iterator");
416 if(*block != *our_metadata_.blocks[i])
417 return die_("metadata block mismatch");
421 next_ok = iterator.next();
422 } while(i < our_metadata_.num_blocks && next_ok);
425 return die_("chain has more blocks than expected");
427 if(i < our_metadata_.num_blocks)
428 return die_("short block count in chain");
430 if(0 != current_block) {
431 printf("CURRENT_POSITION... ");
434 if(*current_block != *our_metadata_.blocks[current_position])
435 return die_("metadata block mismatch");
443 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
448 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
449 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
451 printf("content... ");
455 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
458 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
460 /* don't bother checking if we've already hit an error */
464 printf("%d... ", mc_our_block_number_);
467 if(!ignore_metadata_) {
468 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
469 (void)die_("got more metadata blocks than expected");
470 error_occurred_ = true;
473 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
474 (void)die_("metadata block mismatch");
475 error_occurred_ = true;
480 mc_our_block_number_++;
483 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
485 error_occurred_ = true;
486 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
489 static bool generate_file_(bool include_extras, bool is_ogg)
491 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
492 ::FLAC__StreamMetadata *metadata[4];
493 unsigned i = 0, n = 0;
495 printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
497 while(our_metadata_.num_blocks > 0)
498 delete_from_our_metadata_(0);
500 streaminfo.is_last = false;
501 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
502 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
503 streaminfo.data.stream_info.min_blocksize = 576;
504 streaminfo.data.stream_info.max_blocksize = 576;
505 streaminfo.data.stream_info.min_framesize = 0;
506 streaminfo.data.stream_info.max_framesize = 0;
507 streaminfo.data.stream_info.sample_rate = 44100;
508 streaminfo.data.stream_info.channels = 1;
509 streaminfo.data.stream_info.bits_per_sample = 8;
510 streaminfo.data.stream_info.total_samples = 0;
511 memset(streaminfo.data.stream_info.md5sum, 0, 16);
514 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
515 vorbiscomment.is_last = false;
516 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
517 vorbiscomment.length = (4 + vendor_string_length) + 4;
518 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
519 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
520 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
521 vorbiscomment.data.vorbis_comment.num_comments = 0;
522 vorbiscomment.data.vorbis_comment.comments = 0;
526 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
527 return die_("priming our metadata");
528 cuesheet->is_last = false;
529 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
530 cuesheet->data.cue_sheet.lead_in = 123;
531 cuesheet->data.cue_sheet.is_cd = false;
532 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
533 return die_("priming our metadata");
534 cuesheet->data.cue_sheet.tracks[0].number = 1;
535 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
536 return die_("priming our metadata");
540 picture.is_last = false;
541 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
544 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
545 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
546 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
547 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
548 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
549 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
550 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
551 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
554 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
555 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
556 picture.length += strlen(picture.data.picture.mime_type);
557 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
558 picture.length += strlen((const char *)picture.data.picture.description);
559 picture.data.picture.width = 300;
560 picture.data.picture.height = 300;
561 picture.data.picture.depth = 24;
562 picture.data.picture.colors = 0;
563 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
564 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
565 picture.length += picture.data.picture.data_length;
568 padding.is_last = true;
569 padding.type = ::FLAC__METADATA_TYPE_PADDING;
570 padding.length = 1234;
572 metadata[n++] = &vorbiscomment;
574 metadata[n++] = cuesheet;
575 metadata[n++] = &picture;
577 metadata[n++] = &padding;
579 FLAC::Metadata::StreamInfo s(&streaminfo);
580 FLAC::Metadata::VorbisComment v(&vorbiscomment);
581 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
582 FLAC::Metadata::Picture pi(&picture);
583 FLAC::Metadata::Padding p(&padding);
585 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
586 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
587 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
588 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
589 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
591 return die_("priming our metadata");
593 if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
594 return die_("creating the encoded file");
596 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
597 free(picture.data.picture.mime_type);
598 free(picture.data.picture.description);
599 free(picture.data.picture.data);
604 static bool test_file_(bool is_ogg, bool ignore_metadata)
606 const char *filename = flacfilename(is_ogg);
607 OurFileDecoder decoder(ignore_metadata);
609 mc_our_block_number_ = 0;
610 decoder.error_occurred_ = false;
612 printf("\ttesting '%s'... ", filename);
615 if(!decoder.is_valid())
616 return die_("couldn't allocate decoder instance");
618 decoder.set_md5_checking(true);
619 decoder.set_metadata_respond_all();
620 if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
621 (void)decoder.finish();
622 return die_("initializing decoder\n");
624 if(!decoder.process_until_end_of_stream()) {
625 (void)decoder.finish();
626 return die_("decoding file\n");
629 (void)decoder.finish();
631 if(decoder.error_occurred_)
634 if(mc_our_block_number_ != our_metadata_.num_blocks)
635 return die_("short metadata block count");
641 static bool change_stats_(const char *filename, bool read_only)
643 if(!grabbag__file_change_stats(filename, read_only))
644 return die_("during grabbag__file_change_stats()");
649 static bool remove_file_(const char *filename)
651 while(our_metadata_.num_blocks > 0)
652 delete_from_our_metadata_(0);
654 if(!grabbag__file_remove_file(filename))
655 return die_("removing file");
660 static bool test_level_0_()
662 FLAC::Metadata::StreamInfo streaminfo;
664 printf("\n\n++++++ testing level 0 interface\n");
666 if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
669 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
672 printf("testing FLAC::Metadata::get_streaminfo()... ");
674 if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
675 return die_("during FLAC::Metadata::get_streaminfo()");
677 /* check to see if some basic data matches (c.f. generate_file_()) */
678 if(streaminfo.get_channels() != 1)
679 return die_("mismatch in streaminfo.get_channels()");
680 if(streaminfo.get_bits_per_sample() != 8)
681 return die_("mismatch in streaminfo.get_bits_per_sample()");
682 if(streaminfo.get_sample_rate() != 44100)
683 return die_("mismatch in streaminfo.get_sample_rate()");
684 if(streaminfo.get_min_blocksize() != 576)
685 return die_("mismatch in streaminfo.get_min_blocksize()");
686 if(streaminfo.get_max_blocksize() != 576)
687 return die_("mismatch in streaminfo.get_max_blocksize()");
692 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
694 FLAC::Metadata::VorbisComment *tags = 0;
696 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
697 return die_("during FLAC::Metadata::get_tags()");
699 /* check to see if some basic data matches (c.f. generate_file_()) */
700 if(tags->get_num_comments() != 0)
701 return die_("mismatch in tags->get_num_comments()");
709 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
711 FLAC::Metadata::VorbisComment tags;
713 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
714 return die_("during FLAC::Metadata::get_tags()");
716 /* check to see if some basic data matches (c.f. generate_file_()) */
717 if(tags.get_num_comments() != 0)
718 return die_("mismatch in tags.get_num_comments()");
724 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
726 FLAC::Metadata::CueSheet *cuesheet = 0;
728 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
729 return die_("during FLAC::Metadata::get_cuesheet()");
731 /* check to see if some basic data matches (c.f. generate_file_()) */
732 if(cuesheet->get_lead_in() != 123)
733 return die_("mismatch in cuesheet->get_lead_in()");
741 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
743 FLAC::Metadata::CueSheet cuesheet;
745 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
746 return die_("during FLAC::Metadata::get_cuesheet()");
748 /* check to see if some basic data matches (c.f. generate_file_()) */
749 if(cuesheet.get_lead_in() != 123)
750 return die_("mismatch in cuesheet.get_lead_in()");
756 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
758 FLAC::Metadata::Picture *picture = 0;
760 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)))
761 return die_("during FLAC::Metadata::get_picture()");
763 /* check to see if some basic data matches (c.f. generate_file_()) */
764 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
765 return die_("mismatch in picture->get_type ()");
773 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
775 FLAC::Metadata::Picture picture;
777 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)))
778 return die_("during FLAC::Metadata::get_picture()");
780 /* check to see if some basic data matches (c.f. generate_file_()) */
781 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
782 return die_("mismatch in picture->get_type ()");
787 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
793 static bool test_level_1_()
795 FLAC::Metadata::Prototype *block;
796 FLAC::Metadata::StreamInfo *streaminfo;
797 FLAC::Metadata::Padding *padding;
798 FLAC::Metadata::Application *app;
799 FLAC__byte data[1000];
800 unsigned our_current_position = 0;
802 // initialize 'data' to avoid Valgrind errors
803 memset(data, 0, sizeof(data));
805 printf("\n\n++++++ testing level 1 interface\n");
807 /************************************************************/
809 printf("simple iterator on read-only file\n");
811 if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
814 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
817 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
820 FLAC::Metadata::SimpleIterator iterator;
822 if(!iterator.is_valid())
823 return die_("iterator.is_valid() returned false");
825 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
826 return die_("iterator.init() returned false");
828 printf("is writable = %u\n", (unsigned)iterator.is_writable());
829 if(iterator.is_writable())
830 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
832 printf("iterate forwards\n");
834 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
835 return die_("expected STREAMINFO type from iterator.get_block_type()");
836 if(0 == (block = iterator.get_block()))
837 return die_("getting block 0");
838 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
839 return die_("expected STREAMINFO type");
840 if(block->get_is_last())
841 return die_("expected is_last to be false");
842 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
843 return die_("bad STREAMINFO length");
844 /* check to see if some basic data matches (c.f. generate_file_()) */
845 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
846 FLAC__ASSERT(0 != streaminfo);
847 if(streaminfo->get_channels() != 1)
848 return die_("mismatch in channels");
849 if(streaminfo->get_bits_per_sample() != 8)
850 return die_("mismatch in bits_per_sample");
851 if(streaminfo->get_sample_rate() != 44100)
852 return die_("mismatch in sample_rate");
853 if(streaminfo->get_min_blocksize() != 576)
854 return die_("mismatch in min_blocksize");
855 if(streaminfo->get_max_blocksize() != 576)
856 return die_("mismatch in max_blocksize");
857 // we will delete streaminfo a little later when we're really done with it...
860 return die_("forward iterator ended early");
861 our_current_position++;
864 return die_("forward iterator ended early");
865 our_current_position++;
867 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
868 return die_("expected PADDING type from iterator.get_block_type()");
869 if(0 == (block = iterator.get_block()))
870 return die_("getting block 1");
871 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
872 return die_("expected PADDING type");
873 if(!block->get_is_last())
874 return die_("expected is_last to be true");
875 /* check to see if some basic data matches (c.f. generate_file_()) */
876 if(block->get_length() != 1234)
877 return die_("bad PADDING length");
881 return die_("forward iterator returned true but should have returned false");
883 printf("iterate backwards\n");
885 return die_("reverse iterator ended early");
887 return die_("reverse iterator ended early");
889 return die_("reverse iterator returned true but should have returned false");
891 printf("testing iterator.set_block() on read-only file...\n");
893 if(!iterator.set_block(streaminfo, false))
894 printf("PASSED. iterator.set_block() returned false like it should\n");
896 return die_("iterator.set_block() returned true but shouldn't have");
900 /************************************************************/
902 printf("simple iterator on writable file\n");
904 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
907 printf("creating APPLICATION block\n");
909 if(0 == (app = new FLAC::Metadata::Application()))
910 return die_("new FLAC::Metadata::Application()");
911 app->set_id((const unsigned char *)"duh");
913 printf("creating PADDING block\n");
915 if(0 == (padding = new FLAC::Metadata::Padding()))
916 return die_("new FLAC::Metadata::Padding()");
917 padding->set_length(20);
919 FLAC::Metadata::SimpleIterator iterator;
921 if(!iterator.is_valid())
922 return die_("iterator.is_valid() returned false");
924 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
925 return die_("iterator.init() returned false");
926 our_current_position = 0;
928 printf("is writable = %u\n", (unsigned)iterator.is_writable());
930 printf("[S]VP\ttry to write over STREAMINFO block...\n");
931 if(!iterator.set_block(app, false))
932 printf("\titerator.set_block() returned false like it should\n");
934 return die_("iterator.set_block() returned true but shouldn't have");
936 printf("[S]VP\tnext\n");
938 return die_("iterator ended early\n");
939 our_current_position++;
941 printf("S[V]P\tnext\n");
943 return die_("iterator ended early\n");
944 our_current_position++;
946 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
947 padding->set_length(25);
948 if(!iterator.insert_block_after(padding, false))
949 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
950 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
953 printf("SVP[P]\tprev\n");
955 return die_("iterator ended early\n");
956 our_current_position--;
958 printf("SV[P]P\tprev\n");
960 return die_("iterator ended early\n");
961 our_current_position--;
963 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
964 padding->set_length(30);
965 if(!iterator.insert_block_after(padding, false))
966 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
967 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
970 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
973 printf("SV[P]PP\tprev\n");
975 return die_("iterator ended early\n");
976 our_current_position--;
978 printf("S[V]PPP\tprev\n");
980 return die_("iterator ended early\n");
981 our_current_position--;
983 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
984 if(iterator.delete_block(false))
985 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
987 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
990 printf("[S]VPPP\tnext\n");
992 return die_("iterator ended early\n");
993 our_current_position++;
995 printf("S[V]PPP\tnext\n");
997 return die_("iterator ended early\n");
998 our_current_position++;
1000 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
1001 if(!iterator.delete_block(true))
1002 return die_ss_("iterator.delete_block(true)", iterator);
1003 our_current_position--;
1005 printf("S[V]PPP\tnext\n");
1006 if(!iterator.next())
1007 return die_("iterator ended early\n");
1008 our_current_position++;
1010 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1011 if(!iterator.delete_block(false))
1012 return die_ss_("iterator.delete_block(false)", iterator);
1013 delete_from_our_metadata_(our_current_position--);
1015 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1018 printf("S[V]PP\tnext\n");
1019 if(!iterator.next())
1020 return die_("iterator ended early\n");
1021 our_current_position++;
1023 printf("SV[P]P\tnext\n");
1024 if(!iterator.next())
1025 return die_("iterator ended early\n");
1026 our_current_position++;
1028 printf("SVP[P]\tdelete (last block), replace with padding\n");
1029 if(!iterator.delete_block(true))
1030 return die_ss_("iterator.delete_block(false)", iterator);
1031 our_current_position--;
1033 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1036 printf("SV[P]P\tnext\n");
1037 if(!iterator.next())
1038 return die_("iterator ended early\n");
1039 our_current_position++;
1041 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1042 if(!iterator.delete_block(false))
1043 return die_ss_("iterator.delete_block(false)", iterator);
1044 delete_from_our_metadata_(our_current_position--);
1046 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1049 printf("SV[P]\tprev\n");
1050 if(!iterator.prev())
1051 return die_("iterator ended early\n");
1052 our_current_position--;
1054 printf("S[V]P\tprev\n");
1055 if(!iterator.prev())
1056 return die_("iterator ended early\n");
1057 our_current_position--;
1059 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1060 FLAC__ASSERT(our_current_position == 0);
1061 block = iterator.get_block();
1062 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1063 FLAC__ASSERT(0 != streaminfo);
1064 streaminfo->set_sample_rate(32000);
1065 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1066 return die_("copying object");
1067 if(!iterator.set_block(block, false))
1068 return die_ss_("iterator.set_block(block, false)", iterator);
1071 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1074 printf("[S]VP\tnext\n");
1075 if(!iterator.next())
1076 return die_("iterator ended early\n");
1077 our_current_position++;
1079 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1080 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1081 if(!iterator.insert_block_after(app, true))
1082 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1083 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1085 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1087 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1090 printf("SV[A]P\tnext\n");
1091 if(!iterator.next())
1092 return die_("iterator ended early\n");
1093 our_current_position++;
1095 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1096 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1097 if(!iterator.set_block(app, true))
1098 return die_ss_("iterator.set_block(app, true)", iterator);
1099 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1101 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1103 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1106 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1107 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1108 if(!app->set_data(data, sizeof(data), true))
1109 return die_("setting APPLICATION data");
1110 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1111 return die_("copying object");
1112 if(!iterator.set_block(app, false))
1113 return die_ss_("iterator.set_block(app, false)", iterator);
1115 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1118 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1119 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1120 if(!app->set_data(data, 12, true))
1121 return die_("setting APPLICATION data");
1122 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1123 return die_("copying object");
1124 if(!iterator.set_block(app, false))
1125 return die_ss_("iterator.set_block(app, false)", iterator);
1127 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1130 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1131 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1132 if(!app->set_data(data, sizeof(data), true))
1133 return die_("setting APPLICATION data");
1134 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1135 return die_("copying object");
1136 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1137 if(!iterator.set_block(app, true))
1138 return die_ss_("iterator.set_block(app, true)", iterator);
1140 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1143 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1144 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1145 if(!app->set_data(data, 23, 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(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1150 return die_("copying object");
1151 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1152 if(!iterator.set_block(app, true))
1153 return die_ss_("iterator.set_block(app, true)", iterator);
1155 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1158 printf("SVA[A]PP\tnext\n");
1159 if(!iterator.next())
1160 return die_("iterator ended early\n");
1161 our_current_position++;
1163 printf("SVAA[P]P\tnext\n");
1164 if(!iterator.next())
1165 return die_("iterator ended early\n");
1166 our_current_position++;
1168 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1169 padding->set_length(5);
1170 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1171 return die_("copying object");
1172 if(!iterator.set_block(padding, false))
1173 return die_ss_("iterator.set_block(padding, false)", iterator);
1175 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1178 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1179 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1180 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1181 return die_("copying object");
1182 if(!iterator.set_block(app, false))
1183 return die_ss_("iterator.set_block(app, false)", iterator);
1185 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1188 printf("SVAAP[A]\tset PADDING (equal)\n");
1189 padding->set_length(27);
1190 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1191 return die_("copying object");
1192 if(!iterator.set_block(padding, false))
1193 return die_ss_("iterator.set_block(padding, false)", iterator);
1195 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1198 printf("SVAAP[P]\tprev\n");
1199 if(!iterator.prev())
1200 return die_("iterator ended early\n");
1201 our_current_position--;
1203 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1204 if(!iterator.delete_block(false))
1205 return die_ss_("iterator.delete_block(false)", iterator);
1206 delete_from_our_metadata_(our_current_position--);
1208 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1211 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1212 if(!iterator.delete_block(false))
1213 return die_ss_("iterator.delete_block(false)", iterator);
1214 delete_from_our_metadata_(our_current_position--);
1216 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1219 printf("SV[A]P\tnext\n");
1220 if(!iterator.next())
1221 return die_("iterator ended early\n");
1222 our_current_position++;
1224 printf("SVA[P]\tinsert PADDING after\n");
1225 padding->set_length(5);
1226 if(!iterator.insert_block_after(padding, false))
1227 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1228 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1231 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1234 printf("SVAP[P]\tprev\n");
1235 if(!iterator.prev())
1236 return die_("iterator ended early\n");
1237 our_current_position--;
1239 printf("SVA[P]P\tprev\n");
1240 if(!iterator.prev())
1241 return die_("iterator ended early\n");
1242 our_current_position--;
1244 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1245 if(!app->set_data(data, 32, true))
1246 return die_("setting APPLICATION data");
1247 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1248 return die_("copying object");
1249 if(!iterator.set_block(app, true))
1250 return die_ss_("iterator.set_block(app, true)", iterator);
1252 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1255 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1256 if(!app->set_data(data, 60, true))
1257 return die_("setting APPLICATION data");
1258 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1259 return die_("copying object");
1260 if(!iterator.set_block(app, true))
1261 return die_ss_("iterator.set_block(app, true)", iterator);
1263 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1266 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1267 if(!app->set_data(data, 87, true))
1268 return die_("setting APPLICATION data");
1269 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1270 return die_("copying object");
1271 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1272 if(!iterator.set_block(app, true))
1273 return die_ss_("iterator.set_block(app, true)", iterator);
1275 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1278 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1279 if(!app->set_data(data, 91, true))
1280 return die_("setting APPLICATION data");
1281 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1282 return die_("copying object");
1283 delete_from_our_metadata_(our_current_position+1);
1284 if(!iterator.set_block(app, true))
1285 return die_ss_("iterator.set_block(app, true)", iterator);
1287 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1290 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1291 if(!app->set_data(data, 100, true))
1292 return die_("setting APPLICATION data");
1293 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1294 return die_("copying object");
1295 delete_from_our_metadata_(our_current_position+1);
1296 our_metadata_.blocks[our_current_position]->set_is_last(true);
1297 if(!iterator.set_block(app, true))
1298 return die_ss_("iterator.set_block(app, true)", iterator);
1300 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1303 printf("SV[A]\tset PADDING (equal size)\n");
1304 padding->set_length(app->get_length());
1305 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1306 return die_("copying object");
1307 if(!iterator.set_block(padding, true))
1308 return die_ss_("iterator.set_block(padding, true)", iterator);
1310 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1313 printf("SV[P]\tinsert PADDING after\n");
1314 if(!iterator.insert_block_after(padding, false))
1315 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1316 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1319 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1322 printf("SVP[P]\tinsert PADDING after\n");
1323 padding->set_length(5);
1324 if(!iterator.insert_block_after(padding, false))
1325 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1326 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1329 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1332 printf("SVPP[P]\tprev\n");
1333 if(!iterator.prev())
1334 return die_("iterator ended early\n");
1335 our_current_position--;
1337 printf("SVP[P]P\tprev\n");
1338 if(!iterator.prev())
1339 return die_("iterator ended early\n");
1340 our_current_position--;
1342 printf("SV[P]PP\tprev\n");
1343 if(!iterator.prev())
1344 return die_("iterator ended early\n");
1345 our_current_position--;
1347 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1348 if(!app->set_data(data, 101, true))
1349 return die_("setting APPLICATION data");
1350 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1351 return die_("copying object");
1352 if(!iterator.insert_block_after(app, true))
1353 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1355 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1358 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1359 if(!iterator.delete_block(false))
1360 return die_ss_("iterator.delete_block(false)", iterator);
1361 delete_from_our_metadata_(our_current_position--);
1363 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1366 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1367 if(!app->set_data(data, 97, true))
1368 return die_("setting APPLICATION data");
1369 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1370 return die_("copying object");
1371 if(!iterator.insert_block_after(app, true))
1372 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1374 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1377 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1378 if(!iterator.delete_block(false))
1379 return die_ss_("iterator.delete_block(false)", iterator);
1380 delete_from_our_metadata_(our_current_position--);
1382 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1385 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1386 if(!app->set_data(data, 100, true))
1387 return die_("setting APPLICATION data");
1388 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1389 return die_("copying object");
1390 delete_from_our_metadata_(our_current_position+1);
1391 if(!iterator.insert_block_after(app, true))
1392 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1394 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1397 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1398 if(!iterator.delete_block(false))
1399 return die_ss_("iterator.delete_block(false)", iterator);
1400 delete_from_our_metadata_(our_current_position--);
1402 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1405 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1406 if(!app->set_data(data, 96, true))
1407 return die_("setting APPLICATION data");
1408 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1409 return die_("copying object");
1410 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1411 if(!iterator.insert_block_after(app, true))
1412 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1414 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1417 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1418 if(!iterator.delete_block(false))
1419 return die_ss_("iterator.delete_block(false)", iterator);
1420 delete_from_our_metadata_(our_current_position--);
1422 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1425 printf("S[V]PP\tnext\n");
1426 if(!iterator.next())
1427 return die_("iterator ended early\n");
1428 our_current_position++;
1430 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1431 if(!iterator.delete_block(false))
1432 return die_ss_("iterator.delete_block(false)", iterator);
1433 delete_from_our_metadata_(our_current_position--);
1435 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1438 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1439 if(!app->set_data(data, 1, true))
1440 return die_("setting APPLICATION data");
1441 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1442 return die_("copying object");
1443 delete_from_our_metadata_(our_current_position+1);
1444 if(!iterator.insert_block_after(app, true))
1445 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1447 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1454 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1460 static bool test_level_2_(bool filename_based, bool is_ogg)
1462 FLAC::Metadata::Prototype *block;
1463 FLAC::Metadata::StreamInfo *streaminfo;
1464 FLAC::Metadata::Application *app;
1465 FLAC::Metadata::Padding *padding;
1466 FLAC__byte data[2000];
1467 unsigned our_current_position;
1469 // initialize 'data' to avoid Valgrind errors
1470 memset(data, 0, sizeof(data));
1472 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1474 printf("generate read-only file\n");
1476 if(!generate_file_(/*include_extras=*/false, is_ogg))
1479 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1482 printf("create chain\n");
1483 FLAC::Metadata::Chain chain;
1484 if(!chain.is_valid())
1485 return die_("allocating memory for chain");
1487 printf("read chain\n");
1489 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1490 return die_c_("reading chain", chain.status());
1492 printf("[S]VP\ttest initial metadata\n");
1494 if(!compare_chain_(chain, 0, 0))
1496 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1502 printf("switch file to read-write\n");
1504 if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1507 printf("create iterator\n");
1509 FLAC::Metadata::Iterator iterator;
1510 if(!iterator.is_valid())
1511 return die_("allocating memory for iterator");
1513 our_current_position = 0;
1515 iterator.init(chain);
1517 if(0 == (block = iterator.get_block()))
1518 return die_("getting block from iterator");
1520 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1522 printf("[S]VP\tmodify STREAMINFO, write\n");
1524 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1525 FLAC__ASSERT(0 != streaminfo);
1526 streaminfo->set_sample_rate(32000);
1527 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1528 return die_("copying object");
1531 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1532 return die_c_("during chain.write(false, true)", chain.status());
1533 block = iterator.get_block();
1534 if(!compare_chain_(chain, our_current_position, block))
1537 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1540 printf("[S]VP\tnext\n");
1541 if(!iterator.next())
1542 return die_("iterator ended early\n");
1543 our_current_position++;
1545 printf("S[V]P\tnext\n");
1546 if(!iterator.next())
1547 return die_("iterator ended early\n");
1548 our_current_position++;
1550 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1551 if(0 == (block = iterator.get_block()))
1552 return die_("getting block from iterator");
1553 if(0 == (app = new FLAC::Metadata::Application()))
1554 return die_("new FLAC::Metadata::Application()");
1555 app->set_id((const unsigned char *)"duh");
1556 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1557 return die_("setting APPLICATION data");
1559 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1560 return die_("copying object");
1561 if(!iterator.set_block(app))
1562 return die_c_("iterator.set_block(app)", chain.status());
1564 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1565 return die_c_("during chain.write(false, false)", chain.status());
1566 block = iterator.get_block();
1567 if(!compare_chain_(chain, our_current_position, block))
1570 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1573 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1574 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1575 return die_("copying object");
1576 if(!app->set_data(data, 26, true))
1577 return die_("setting APPLICATION data");
1578 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1579 return die_("copying object");
1580 if(!iterator.set_block(app))
1581 return die_c_("iterator.set_block(app)", chain.status());
1583 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1584 return die_c_("during chain.write(false, false)", chain.status());
1585 block = iterator.get_block();
1586 if(!compare_chain_(chain, our_current_position, block))
1589 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1592 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1593 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1594 return die_("copying object");
1595 if(!app->set_data(data, 28, true))
1596 return die_("setting APPLICATION data");
1597 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1598 return die_("copying object");
1599 if(!iterator.set_block(app))
1600 return die_c_("iterator.set_block(app)", chain.status());
1602 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1603 return die_c_("during chain.write(false, false)", chain.status());
1604 block = iterator.get_block();
1605 if(!compare_chain_(chain, our_current_position, block))
1608 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1611 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1612 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1613 return die_("copying object");
1614 if(!app->set_data(data, 36, true))
1615 return die_("setting APPLICATION data");
1616 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1617 return die_("copying object");
1618 if(!iterator.set_block(app))
1619 return die_c_("iterator.set_block(app)", chain.status());
1621 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1622 return die_c_("during chain.write(false, false)", chain.status());
1623 block = iterator.get_block();
1624 if(!compare_chain_(chain, our_current_position, block))
1627 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1630 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1631 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1632 return die_("copying object");
1633 if(!app->set_data(data, 33, true))
1634 return die_("setting APPLICATION data");
1635 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1636 return die_("copying object");
1637 if(!iterator.set_block(app))
1638 return die_c_("iterator.set_block(app)", chain.status());
1640 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1641 return die_c_("during chain.write(true, false)", chain.status());
1642 block = iterator.get_block();
1643 if(!compare_chain_(chain, our_current_position, block))
1646 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1649 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1650 if(0 == (padding = new FLAC::Metadata::Padding()))
1651 return die_("creating PADDING block");
1652 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1653 return die_("copying object");
1654 if(!app->set_data(data, 29, true))
1655 return die_("setting APPLICATION data");
1656 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1657 return die_("copying object");
1658 padding->set_length(0);
1659 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1660 return die_("internal error");
1661 if(!iterator.set_block(app))
1662 return die_c_("iterator.set_block(app)", chain.status());
1664 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1665 return die_c_("during chain.write(true, false)", chain.status());
1666 block = iterator.get_block();
1667 if(!compare_chain_(chain, our_current_position, block))
1670 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1673 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1674 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1675 return die_("copying object");
1676 if(!app->set_data(data, 16, true))
1677 return die_("setting APPLICATION data");
1678 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1679 return die_("copying object");
1680 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1681 if(!iterator.set_block(app))
1682 return die_c_("iterator.set_block(app)", chain.status());
1684 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1685 return die_c_("during chain.write(true, false)", chain.status());
1686 block = iterator.get_block();
1687 if(!compare_chain_(chain, our_current_position, block))
1690 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1693 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1694 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1695 return die_("copying object");
1696 if(!app->set_data(data, 50, true))
1697 return die_("setting APPLICATION data");
1698 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1699 return die_("copying object");
1700 if(!iterator.set_block(app))
1701 return die_c_("iterator.set_block(app)", chain.status());
1703 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1704 return die_c_("during chain.write(true, false)", chain.status());
1705 block = iterator.get_block();
1706 if(!compare_chain_(chain, our_current_position, block))
1709 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1712 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1713 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1714 return die_("copying object");
1715 if(!app->set_data(data, 56, true))
1716 return die_("setting APPLICATION data");
1717 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1718 return die_("copying object");
1719 add_to_padding_length_(our_current_position+1, -(56 - 50));
1720 if(!iterator.set_block(app))
1721 return die_c_("iterator.set_block(app)", chain.status());
1723 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1724 return die_c_("during chain.write(true, false)", chain.status());
1725 block = iterator.get_block();
1726 if(!compare_chain_(chain, our_current_position, block))
1729 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1732 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1733 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1734 return die_("copying object");
1735 if(!app->set_data(data, 67, true))
1736 return die_("setting APPLICATION data");
1737 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1738 return die_("copying object");
1739 delete_from_our_metadata_(our_current_position+1);
1740 if(!iterator.set_block(app))
1741 return die_c_("iterator.set_block(app)", chain.status());
1743 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1744 return die_c_("during chain.write(true, false)", chain.status());
1745 block = iterator.get_block();
1746 if(!compare_chain_(chain, our_current_position, block))
1749 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1752 printf("SV[A]\tprev\n");
1753 if(!iterator.prev())
1754 return die_("iterator ended early\n");
1755 our_current_position--;
1757 printf("S[V]A\tprev\n");
1758 if(!iterator.prev())
1759 return die_("iterator ended early\n");
1760 our_current_position--;
1762 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1763 if(0 == (padding = new FLAC::Metadata::Padding()))
1764 return die_("creating PADDING block");
1765 padding->set_length(30);
1766 if(!iterator.insert_block_before(padding))
1767 printf("\titerator.insert_block_before() returned false like it should\n");
1769 return die_("iterator.insert_block_before() should have returned false");
1771 printf("[S]VA\tnext\n");
1772 if(!iterator.next())
1773 return die_("iterator ended early\n");
1774 our_current_position++;
1776 printf("S[V]A\tinsert PADDING after\n");
1777 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1778 return die_("copying metadata");
1779 if(!iterator.insert_block_after(padding))
1780 return die_("iterator.insert_block_after(padding)");
1782 block = iterator.get_block();
1783 if(!compare_chain_(chain, our_current_position, block))
1787 printf("SV[P]A\tinsert PADDING before\n");
1788 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1789 return die_("creating PADDING block");
1790 padding->set_length(17);
1791 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1792 return die_("copying metadata");
1793 if(!iterator.insert_block_before(padding))
1794 return die_("iterator.insert_block_before(padding)");
1796 block = iterator.get_block();
1797 if(!compare_chain_(chain, our_current_position, block))
1801 printf("SV[P]PA\tinsert PADDING before\n");
1802 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1803 return die_("creating PADDING block");
1804 padding->set_length(0);
1805 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1806 return die_("copying metadata");
1807 if(!iterator.insert_block_before(padding))
1808 return die_("iterator.insert_block_before(padding)");
1810 block = iterator.get_block();
1811 if(!compare_chain_(chain, our_current_position, block))
1815 printf("SV[P]PPA\tnext\n");
1816 if(!iterator.next())
1817 return die_("iterator ended early\n");
1818 our_current_position++;
1820 printf("SVP[P]PA\tnext\n");
1821 if(!iterator.next())
1822 return die_("iterator ended early\n");
1823 our_current_position++;
1825 printf("SVPP[P]A\tnext\n");
1826 if(!iterator.next())
1827 return die_("iterator ended early\n");
1828 our_current_position++;
1830 printf("SVPPP[A]\tinsert PADDING after\n");
1831 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1832 return die_("creating PADDING block");
1833 padding->set_length(57);
1834 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1835 return die_("copying metadata");
1836 if(!iterator.insert_block_after(padding))
1837 return die_("iterator.insert_block_after(padding)");
1839 block = iterator.get_block();
1840 if(!compare_chain_(chain, our_current_position, block))
1844 printf("SVPPPA[P]\tinsert PADDING before\n");
1845 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1846 return die_("creating PADDING block");
1847 padding->set_length(99);
1848 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1849 return die_("copying metadata");
1850 if(!iterator.insert_block_before(padding))
1851 return die_("iterator.insert_block_before(padding)");
1853 block = iterator.get_block();
1854 if(!compare_chain_(chain, our_current_position, block))
1859 our_current_position = 0;
1861 printf("SVPPPAPP\tmerge padding\n");
1862 chain.merge_padding();
1863 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1864 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1865 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1866 delete_from_our_metadata_(7);
1867 delete_from_our_metadata_(4);
1868 delete_from_our_metadata_(3);
1870 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1871 return die_c_("during chain.write(true, false)", chain.status());
1872 if(!compare_chain_(chain, 0, 0))
1874 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1877 printf("SVPAP\tsort padding\n");
1878 chain.sort_padding();
1879 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1880 delete_from_our_metadata_(2);
1882 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1883 return die_c_("during chain.write(true, false)", chain.status());
1884 if(!compare_chain_(chain, 0, 0))
1886 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1889 printf("create iterator\n");
1891 FLAC::Metadata::Iterator iterator;
1892 if(!iterator.is_valid())
1893 return die_("allocating memory for iterator");
1895 our_current_position = 0;
1897 iterator.init(chain);
1899 printf("[S]VAP\tnext\n");
1900 if(!iterator.next())
1901 return die_("iterator ended early\n");
1902 our_current_position++;
1904 printf("S[V]AP\tnext\n");
1905 if(!iterator.next())
1906 return die_("iterator ended early\n");
1907 our_current_position++;
1909 printf("SV[A]P\tdelete middle block, replace with padding\n");
1910 if(0 == (padding = new FLAC::Metadata::Padding()))
1911 return die_("creating PADDING block");
1912 padding->set_length(71);
1913 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1914 return die_("copying object");
1915 if(!iterator.delete_block(/*replace_with_padding=*/true))
1916 return die_c_("iterator.delete_block(true)", chain.status());
1918 block = iterator.get_block();
1919 if(!compare_chain_(chain, our_current_position, block))
1923 printf("S[V]PP\tnext\n");
1924 if(!iterator.next())
1925 return die_("iterator ended early\n");
1926 our_current_position++;
1928 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1929 delete_from_our_metadata_(our_current_position--);
1930 if(!iterator.delete_block(/*replace_with_padding=*/false))
1931 return die_c_("iterator.delete_block(false)", chain.status());
1933 block = iterator.get_block();
1934 if(!compare_chain_(chain, our_current_position, block))
1938 printf("S[V]P\tnext\n");
1939 if(!iterator.next())
1940 return die_("iterator ended early\n");
1941 our_current_position++;
1943 printf("SV[P]\tdelete last block, replace with padding\n");
1944 if(0 == (padding = new FLAC::Metadata::Padding()))
1945 return die_("creating PADDING block");
1946 padding->set_length(219);
1947 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1948 return die_("copying object");
1949 if(!iterator.delete_block(/*replace_with_padding=*/true))
1950 return die_c_("iterator.delete_block(true)", chain.status());
1952 block = iterator.get_block();
1953 if(!compare_chain_(chain, our_current_position, block))
1957 printf("S[V]P\tnext\n");
1958 if(!iterator.next())
1959 return die_("iterator ended early\n");
1960 our_current_position++;
1962 printf("SV[P]\tdelete last block, don't replace with padding\n");
1963 delete_from_our_metadata_(our_current_position--);
1964 if(!iterator.delete_block(/*replace_with_padding=*/false))
1965 return die_c_("iterator.delete_block(false)", chain.status());
1967 block = iterator.get_block();
1968 if(!compare_chain_(chain, our_current_position, block))
1972 printf("S[V]\tprev\n");
1973 if(!iterator.prev())
1974 return die_("iterator ended early\n");
1975 our_current_position--;
1977 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1978 if(iterator.delete_block(/*replace_with_padding=*/false))
1979 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1981 block = iterator.get_block();
1982 if(!compare_chain_(chain, our_current_position, block))
1986 } // delete iterator
1987 our_current_position = 0;
1989 printf("SV\tmerge padding\n");
1990 chain.merge_padding();
1992 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1993 return die_c_("during chain.write(false, false)", chain.status());
1994 if(!compare_chain_(chain, 0, 0))
1996 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1999 printf("SV\tsort padding\n");
2000 chain.sort_padding();
2002 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
2003 return die_c_("during chain.write(false, false)", chain.status());
2004 if(!compare_chain_(chain, 0, 0))
2006 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2010 if(!remove_file_(flacfilename(is_ogg)))
2016 static bool test_level_2_misc_(bool is_ogg)
2018 ::FLAC__IOCallbacks callbacks;
2020 memset(&callbacks, 0, sizeof(callbacks));
2021 callbacks.read = (::FLAC__IOCallback_Read)fread;
2022 #ifdef FLAC__VALGRIND_TESTING
2023 callbacks.write = chain_write_cb_;
2025 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2027 callbacks.seek = chain_seek_cb_;
2028 callbacks.tell = chain_tell_cb_;
2029 callbacks.eof = chain_eof_cb_;
2031 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2033 printf("generate file\n");
2035 if(!generate_file_(/*include_extras=*/false, is_ogg))
2038 printf("create chain\n");
2039 FLAC::Metadata::Chain chain;
2040 if(!chain.is_valid())
2041 return die_("allocating chain");
2043 printf("read chain (filename-based)\n");
2045 if(!chain.read(flacfilename(is_ogg)))
2046 return die_c_("reading chain", chain.status());
2048 printf("write chain with wrong method Chain::write(with callbacks)\n");
2050 if(chain.write(/*use_padding=*/false, 0, callbacks))
2051 return die_c_("mismatched write should have failed", chain.status());
2052 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2053 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2054 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2057 printf("read chain (filename-based)\n");
2059 if(!chain.read(flacfilename(is_ogg)))
2060 return die_c_("reading chain", chain.status());
2062 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2064 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2065 return die_c_("mismatched write should have failed", chain.status());
2066 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2067 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2068 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2071 printf("read chain (callback-based)\n");
2073 FILE *file = fopen(flacfilename(is_ogg), "rb");
2075 return die_("opening file");
2076 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2078 return die_c_("reading chain", chain.status());
2083 printf("write chain with wrong method write()\n");
2085 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2086 return die_c_("mismatched write should have failed", chain.status());
2087 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2088 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2089 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2092 printf("read chain (callback-based)\n");
2094 FILE *file = fopen(flacfilename(is_ogg), "rb");
2096 return die_("opening file");
2097 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2099 return die_c_("reading chain", chain.status());
2104 printf("testing Chain::check_if_tempfile_needed()... ");
2106 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2107 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2109 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2111 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2113 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2114 return die_c_("mismatched write should have failed", chain.status());
2115 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2116 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2117 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2120 printf("read chain (callback-based)\n");
2122 FILE *file = fopen(flacfilename(is_ogg), "rb");
2124 return die_("opening file");
2125 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2127 return die_c_("reading chain", chain.status());
2132 printf("create iterator\n");
2134 FLAC::Metadata::Iterator iterator;
2135 if(!iterator.is_valid())
2136 return die_("allocating memory for iterator");
2138 iterator.init(chain);
2140 printf("[S]VP\tnext\n");
2141 if(!iterator.next())
2142 return die_("iterator ended early\n");
2144 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2145 if(!iterator.delete_block(/*replace_with_padding=*/false))
2146 return die_c_("block delete failed\n", chain.status());
2148 printf("testing Chain::check_if_tempfile_needed()... ");
2150 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2151 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2153 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2155 printf("write chain with wrong method Chain::write(with callbacks)\n");
2157 if(chain.write(/*use_padding=*/false, 0, callbacks))
2158 return die_c_("mismatched write should have failed", chain.status());
2159 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2160 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2161 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2164 } // delete iterator
2166 if(!remove_file_(flacfilename(is_ogg)))
2172 bool test_metadata_file_manipulation()
2174 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2176 our_metadata_.num_blocks = 0;
2178 if(!test_level_0_())
2181 if(!test_level_1_())
2184 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2186 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2188 if(!test_level_2_misc_(/*is_ogg=*/false))
2191 if(FLAC_API_SUPPORTS_OGG_FLAC) {
2192 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2194 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2197 /* when ogg flac write is supported, will have to add this: */
2198 if(!test_level_2_misc_(/*is_ogg=*/true))