1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006 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
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <stdlib.h> /* for malloc() */
21 #include <string.h> /* for memcpy()/memset() */
22 #if defined _MSC_VER || defined __MINGW32__
23 #include <sys/utime.h> /* for utime() */
24 #include <io.h> /* for chmod() */
25 //@@@ [2G limit] hacks for MSVC6
29 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
30 #include <utime.h> /* for utime() */
31 #include <unistd.h> /* for chown(), unlink() */
33 #include <sys/stat.h> /* for stat(), maybe chmod() */
34 #include "FLAC/assert.h"
35 #include "FLAC++/decoder.h"
36 #include "FLAC++/metadata.h"
37 #include "share/grabbag.h"
39 #include "test_libs_common/file_utils_flac.h"
42 /******************************************************************************
43 The general strategy of these tests (for interface levels 1 and 2) is
44 to create a dummy FLAC file with a known set of initial metadata
45 blocks, then keep a mirror locally of what we expect the metadata to be
46 after each operation. Then testing becomes a simple matter of running
47 a FLAC::Decoder::File over the dummy file after each operation, comparing
48 the decoded metadata to what's in our local copy. If there are any
49 differences in the metadata, or the actual audio data is corrupted, we
50 will catch it while decoding.
51 ******************************************************************************/
53 class OurFileDecoder: public FLAC::Decoder::File {
55 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
57 bool ignore_metadata_;
60 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
61 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
62 void error_callback(::FLAC__StreamDecoderErrorStatus status);
66 FLAC::Metadata::Prototype *blocks[64];
70 static const char *flacfile_ = "metadata.flac";
72 /* our copy of the metadata in flacfile_ */
73 static OurMetadata our_metadata_;
75 /* the current block number that corresponds to the position of the iterator we are testing */
76 static unsigned mc_our_block_number_ = 0;
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 /* functions for working with our metadata copy */
111 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
114 FLAC::Metadata::Prototype *obj = block;
115 FLAC__ASSERT(position < our_metadata_.num_blocks);
117 if(0 == (obj = FLAC::Metadata::clone(block)))
118 return die_("during FLAC::Metadata::clone()");
120 delete our_metadata_.blocks[position];
121 our_metadata_.blocks[position] = obj;
123 /* set the is_last flags */
124 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
125 our_metadata_.blocks[i]->set_is_last(false);
126 our_metadata_.blocks[i]->set_is_last(true);
131 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
134 FLAC::Metadata::Prototype *obj = block;
136 if(0 == (obj = FLAC::Metadata::clone(block)))
137 return die_("during FLAC::Metadata::clone()");
139 if(position > our_metadata_.num_blocks) {
140 position = our_metadata_.num_blocks;
143 for(i = our_metadata_.num_blocks; i > position; i--)
144 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
146 our_metadata_.blocks[position] = obj;
147 our_metadata_.num_blocks++;
149 /* set the is_last flags */
150 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
151 our_metadata_.blocks[i]->set_is_last(false);
152 our_metadata_.blocks[i]->set_is_last(true);
157 static void delete_from_our_metadata_(unsigned position)
160 FLAC__ASSERT(position < our_metadata_.num_blocks);
161 delete our_metadata_.blocks[position];
162 for(i = position; i < our_metadata_.num_blocks - 1; i++)
163 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
164 our_metadata_.num_blocks--;
166 /* set the is_last flags */
167 if(our_metadata_.num_blocks > 0) {
168 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
169 our_metadata_.blocks[i]->set_is_last(false);
170 our_metadata_.blocks[i]->set_is_last(true);
174 void add_to_padding_length_(unsigned index, int delta)
176 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
177 FLAC__ASSERT(0 != padding);
178 padding->set_length((unsigned)((int)padding->get_length() + delta));
182 * This wad of functions supports filename- and callback-based chain reading/writing.
183 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
185 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
187 static const char *tempfile_suffix = ".metadata_edit";
189 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
191 strcpy(*tempfilename, filename);
192 strcat(*tempfilename, tempfile_suffix);
194 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
200 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
203 (void)fclose(*tempfile);
207 if(0 != *tempfilename) {
208 (void)unlink(*tempfilename);
214 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
216 FLAC__ASSERT(0 != filename);
217 FLAC__ASSERT(0 != tempfile);
218 FLAC__ASSERT(0 != tempfilename);
219 FLAC__ASSERT(0 != *tempfilename);
222 (void)fclose(*tempfile);
226 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
227 /* on some flavors of windows, rename() will fail if the destination already exists */
228 if(unlink(filename) < 0) {
229 cleanup_tempfile_(tempfile, tempfilename);
234 if(0 != rename(*tempfilename, filename)) {
235 cleanup_tempfile_(tempfile, tempfilename);
239 cleanup_tempfile_(tempfile, tempfilename);
244 bool get_file_stats_(const char *filename, struct stat *stats)
246 FLAC__ASSERT(0 != filename);
247 FLAC__ASSERT(0 != stats);
248 return (0 == stat(filename, stats));
251 void set_file_stats_(const char *filename, struct stat *stats)
253 struct utimbuf srctime;
255 FLAC__ASSERT(0 != filename);
256 FLAC__ASSERT(0 != stats);
258 srctime.actime = stats->st_atime;
259 srctime.modtime = stats->st_mtime;
260 (void)chmod(filename, stats->st_mode);
261 (void)utime(filename, &srctime);
262 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
263 (void)chown(filename, stats->st_uid, (gid_t)(-1));
264 (void)chown(filename, (uid_t)(-1), stats->st_gid);
268 #ifdef FLAC__VALGRIND_TESTING
269 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
271 FILE *stream = (FILE*)handle;
272 size_t ret = fwrite(ptr, size, nmemb, stream);
279 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
281 off_t o = (off_t)offset;
282 FLAC__ASSERT(offset == o);
283 return fseeko((FILE*)handle, o, whence);
286 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
288 return ftello((FILE*)handle);
291 static int chain_eof_cb_(::FLAC__IOHandle handle)
293 return feof((FILE*)handle);
296 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
299 return chain.write(use_padding, preserve_file_stats);
301 ::FLAC__IOCallbacks callbacks;
303 memset(&callbacks, 0, sizeof(callbacks));
304 callbacks.read = (::FLAC__IOCallback_Read)fread;
305 #ifdef FLAC__VALGRIND_TESTING
306 callbacks.write = chain_write_cb_;
308 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
310 callbacks.seek = chain_seek_cb_;
311 callbacks.eof = chain_eof_cb_;
313 if(chain.check_if_tempfile_needed(use_padding)) {
315 FILE *file, *tempfile;
317 if(preserve_file_stats) {
318 if(!get_file_stats_(filename, &stats))
321 if(0 == (file = fopen(filename, "rb")))
322 return false; /*@@@ chain status still says OK though */
323 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
325 cleanup_tempfile_(&tempfile, &tempfilename);
326 return false; /*@@@ chain status still says OK though */
328 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
336 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
338 if(preserve_file_stats)
339 set_file_stats_(filename, &stats);
342 FILE *file = fopen(filename, "r+b");
344 return false; /*@@@ chain status still says OK though */
345 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
354 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
357 return chain.read(filename);
359 ::FLAC__IOCallbacks callbacks;
361 memset(&callbacks, 0, sizeof(callbacks));
362 callbacks.read = (::FLAC__IOCallback_Read)fread;
363 callbacks.seek = chain_seek_cb_;
364 callbacks.tell = chain_tell_cb_;
368 FILE *file = fopen(filename, "rb");
370 return false; /*@@@ chain status still says OK though */
371 ret = chain.read((::FLAC__IOHandle)file, callbacks);
378 /* function for comparing our metadata to a FLAC::Metadata::Chain */
380 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
383 FLAC::Metadata::Iterator iterator;
386 printf("\tcomparing chain... ");
389 if(!iterator.is_valid())
390 return die_("allocating memory for iterator");
392 iterator.init(chain);
396 FLAC::Metadata::Prototype *block;
401 if(0 == (block = iterator.get_block()))
402 return die_("getting block from iterator");
404 if(*block != *our_metadata_.blocks[i])
405 return die_("metadata block mismatch");
409 next_ok = iterator.next();
410 } while(i < our_metadata_.num_blocks && next_ok);
413 return die_("chain has more blocks than expected");
415 if(i < our_metadata_.num_blocks)
416 return die_("short block count in chain");
418 if(0 != current_block) {
419 printf("CURRENT_POSITION... ");
422 if(*current_block != *our_metadata_.blocks[current_position])
423 return die_("metadata block mismatch");
431 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
436 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
437 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
439 printf("content... ");
443 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
446 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
448 /* don't bother checking if we've already hit an error */
452 printf("%d... ", mc_our_block_number_);
455 if(!ignore_metadata_) {
456 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
457 (void)die_("got more metadata blocks than expected");
458 error_occurred_ = true;
461 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
462 (void)die_("metadata block mismatch");
463 error_occurred_ = true;
468 mc_our_block_number_++;
471 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
473 error_occurred_ = true;
474 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
477 static bool generate_file_(FLAC__bool include_cuesheet)
479 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
480 ::FLAC__StreamMetadata *metadata[3];
481 unsigned i = 0, n = 0;
483 printf("generating FLAC file for test\n");
485 while(our_metadata_.num_blocks > 0)
486 delete_from_our_metadata_(0);
488 streaminfo.is_last = false;
489 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
490 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
491 streaminfo.data.stream_info.min_blocksize = 576;
492 streaminfo.data.stream_info.max_blocksize = 576;
493 streaminfo.data.stream_info.min_framesize = 0;
494 streaminfo.data.stream_info.max_framesize = 0;
495 streaminfo.data.stream_info.sample_rate = 44100;
496 streaminfo.data.stream_info.channels = 1;
497 streaminfo.data.stream_info.bits_per_sample = 8;
498 streaminfo.data.stream_info.total_samples = 0;
499 memset(streaminfo.data.stream_info.md5sum, 0, 16);
502 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
503 vorbiscomment.is_last = false;
504 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
505 vorbiscomment.length = (4 + vendor_string_length) + 4;
506 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
507 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
508 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
509 vorbiscomment.data.vorbis_comment.num_comments = 0;
510 vorbiscomment.data.vorbis_comment.comments = 0;
514 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
515 return die_("priming our metadata");
516 cuesheet->is_last = false;
517 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
518 cuesheet->data.cue_sheet.lead_in = 123;
519 cuesheet->data.cue_sheet.is_cd = false;
520 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
521 return die_("priming our metadata");
522 cuesheet->data.cue_sheet.tracks[0].number = 1;
523 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
524 return die_("priming our metadata");
527 padding.is_last = true;
528 padding.type = ::FLAC__METADATA_TYPE_PADDING;
529 padding.length = 1234;
531 metadata[n++] = &vorbiscomment;
532 if (include_cuesheet)
533 metadata[n++] = cuesheet;
534 metadata[n++] = &padding;
536 FLAC::Metadata::StreamInfo s(&streaminfo);
537 FLAC::Metadata::VorbisComment v(&vorbiscomment);
538 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
539 FLAC::Metadata::Padding p(&padding);
541 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
542 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
543 (include_cuesheet && !insert_to_our_metadata_(&v, i++, /*copy=*/true)) ||
544 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
546 return die_("priming our metadata");
548 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
549 return die_("creating the encoded file");
551 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
556 static bool test_file_(const char *filename, bool ignore_metadata)
558 OurFileDecoder decoder(ignore_metadata);
560 FLAC__ASSERT(0 != filename);
562 mc_our_block_number_ = 0;
563 decoder.error_occurred_ = false;
565 printf("\ttesting '%s'... ", filename);
568 if(!decoder.is_valid())
569 return die_("couldn't allocate decoder instance");
571 decoder.set_md5_checking(true);
572 decoder.set_metadata_respond_all();
573 if(decoder.init(filename) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
575 return die_("initializing decoder\n");
577 if(!decoder.process_until_end_of_stream()) {
579 return die_("decoding file\n");
584 if(decoder.error_occurred_)
587 if(mc_our_block_number_ != our_metadata_.num_blocks)
588 return die_("short metadata block count");
594 static bool change_stats_(const char *filename, bool read_only)
596 if(!grabbag__file_change_stats(filename, read_only))
597 return die_("during grabbag__file_change_stats()");
602 static bool remove_file_(const char *filename)
604 while(our_metadata_.num_blocks > 0)
605 delete_from_our_metadata_(0);
607 if(!grabbag__file_remove_file(filename))
608 return die_("removing file");
613 static bool test_level_0_()
615 FLAC::Metadata::StreamInfo streaminfo;
617 printf("\n\n++++++ testing level 0 interface\n");
619 if(!generate_file_(/*include_cuesheet=*/true))
622 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
625 printf("testing FLAC::Metadata::get_streaminfo()... ");
627 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
628 return die_("during FLAC::Metadata::get_streaminfo()");
630 /* check to see if some basic data matches (c.f. generate_file_()) */
631 if(streaminfo.get_channels() != 1)
632 return die_("mismatch in streaminfo.get_channels()");
633 if(streaminfo.get_bits_per_sample() != 8)
634 return die_("mismatch in streaminfo.get_bits_per_sample()");
635 if(streaminfo.get_sample_rate() != 44100)
636 return die_("mismatch in streaminfo.get_sample_rate()");
637 if(streaminfo.get_min_blocksize() != 576)
638 return die_("mismatch in streaminfo.get_min_blocksize()");
639 if(streaminfo.get_max_blocksize() != 576)
640 return die_("mismatch in streaminfo.get_max_blocksize()");
645 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
647 FLAC::Metadata::VorbisComment *tags = 0;
649 if(!FLAC::Metadata::get_tags(flacfile_, tags))
650 return die_("during FLAC::Metadata::get_tags()");
652 /* check to see if some basic data matches (c.f. generate_file_()) */
653 if(tags->get_num_comments() != 0)
654 return die_("mismatch in tags->get_num_comments()");
662 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
664 FLAC::Metadata::VorbisComment tags;
666 if(!FLAC::Metadata::get_tags(flacfile_, tags))
667 return die_("during FLAC::Metadata::get_tags()");
669 /* check to see if some basic data matches (c.f. generate_file_()) */
670 if(tags.get_num_comments() != 0)
671 return die_("mismatch in tags.get_num_comments()");
677 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
679 FLAC::Metadata::CueSheet *cuesheet = 0;
681 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
682 return die_("during FLAC::Metadata::get_cuesheet()");
684 /* check to see if some basic data matches (c.f. generate_file_()) */
685 if(cuesheet->get_lead_in() != 123)
686 return die_("mismatch in cuesheet->get_lead_in()");
694 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
696 FLAC::Metadata::CueSheet cuesheet;
698 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
699 return die_("during FLAC::Metadata::get_cuesheet()");
701 /* check to see if some basic data matches (c.f. generate_file_()) */
702 if(cuesheet.get_lead_in() != 123)
703 return die_("mismatch in cuesheet.get_lead_in()");
708 if(!remove_file_(flacfile_))
714 static bool test_level_1_()
716 FLAC::Metadata::Prototype *block;
717 FLAC::Metadata::StreamInfo *streaminfo;
718 FLAC::Metadata::Padding *padding;
719 FLAC::Metadata::Application *app;
720 FLAC__byte data[1000];
721 unsigned our_current_position = 0;
723 // initialize 'data' to avoid Valgrind errors
724 memset(data, 0, sizeof(data));
726 printf("\n\n++++++ testing level 1 interface\n");
728 /************************************************************/
730 printf("simple iterator on read-only file\n");
732 if(!generate_file_(/*include_cuesheet=*/false))
735 if(!change_stats_(flacfile_, /*read_only=*/true))
738 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
741 FLAC::Metadata::SimpleIterator iterator;
743 if(!iterator.is_valid())
744 return die_("iterator.is_valid() returned false");
746 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
747 return die_("iterator.init() returned false");
749 printf("is writable = %u\n", (unsigned)iterator.is_writable());
750 if(iterator.is_writable())
751 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
753 printf("iterate forwards\n");
755 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
756 return die_("expected STREAMINFO type from iterator.get_block_type()");
757 if(0 == (block = iterator.get_block()))
758 return die_("getting block 0");
759 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
760 return die_("expected STREAMINFO type");
761 if(block->get_is_last())
762 return die_("expected is_last to be false");
763 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
764 return die_("bad STREAMINFO length");
765 /* check to see if some basic data matches (c.f. generate_file_()) */
766 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
767 FLAC__ASSERT(0 != streaminfo);
768 if(streaminfo->get_channels() != 1)
769 return die_("mismatch in channels");
770 if(streaminfo->get_bits_per_sample() != 8)
771 return die_("mismatch in bits_per_sample");
772 if(streaminfo->get_sample_rate() != 44100)
773 return die_("mismatch in sample_rate");
774 if(streaminfo->get_min_blocksize() != 576)
775 return die_("mismatch in min_blocksize");
776 if(streaminfo->get_max_blocksize() != 576)
777 return die_("mismatch in max_blocksize");
778 // we will delete streaminfo a little later when we're really done with it...
781 return die_("forward iterator ended early");
782 our_current_position++;
785 return die_("forward iterator ended early");
786 our_current_position++;
788 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
789 return die_("expected PADDING type from iterator.get_block_type()");
790 if(0 == (block = iterator.get_block()))
791 return die_("getting block 1");
792 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
793 return die_("expected PADDING type");
794 if(!block->get_is_last())
795 return die_("expected is_last to be true");
796 /* check to see if some basic data matches (c.f. generate_file_()) */
797 if(block->get_length() != 1234)
798 return die_("bad PADDING length");
802 return die_("forward iterator returned true but should have returned false");
804 printf("iterate backwards\n");
806 return die_("reverse iterator ended early");
808 return die_("reverse iterator ended early");
810 return die_("reverse iterator returned true but should have returned false");
812 printf("testing iterator.set_block() on read-only file...\n");
814 if(!iterator.set_block(streaminfo, false))
815 printf("PASSED. iterator.set_block() returned false like it should\n");
817 return die_("iterator.set_block() returned true but shouldn't have");
821 /************************************************************/
823 printf("simple iterator on writable file\n");
825 if(!change_stats_(flacfile_, /*read-only=*/false))
828 printf("creating APPLICATION block\n");
830 if(0 == (app = new FLAC::Metadata::Application()))
831 return die_("new FLAC::Metadata::Application()");
832 app->set_id((const unsigned char *)"duh");
834 printf("creating PADDING block\n");
836 if(0 == (padding = new FLAC::Metadata::Padding()))
837 return die_("new FLAC::Metadata::Padding()");
838 padding->set_length(20);
840 FLAC::Metadata::SimpleIterator iterator;
842 if(!iterator.is_valid())
843 return die_("iterator.is_valid() returned false");
845 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
846 return die_("iterator.init() returned false");
847 our_current_position = 0;
849 printf("is writable = %u\n", (unsigned)iterator.is_writable());
851 printf("[S]VP\ttry to write over STREAMINFO block...\n");
852 if(!iterator.set_block(app, false))
853 printf("\titerator.set_block() returned false like it should\n");
855 return die_("iterator.set_block() returned true but shouldn't have");
857 printf("[S]VP\tnext\n");
859 return die_("iterator ended early\n");
860 our_current_position++;
862 printf("S[V]P\tnext\n");
864 return die_("iterator ended early\n");
865 our_current_position++;
867 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
868 padding->set_length(25);
869 if(!iterator.insert_block_after(padding, false))
870 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
871 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
874 printf("SVP[P]\tprev\n");
876 return die_("iterator ended early\n");
877 our_current_position--;
879 printf("SV[P]P\tprev\n");
881 return die_("iterator ended early\n");
882 our_current_position--;
884 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
885 padding->set_length(30);
886 if(!iterator.insert_block_after(padding, false))
887 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
888 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
891 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
894 printf("SV[P]PP\tprev\n");
896 return die_("iterator ended early\n");
897 our_current_position--;
899 printf("S[V]PPP\tprev\n");
901 return die_("iterator ended early\n");
902 our_current_position--;
904 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
905 if(iterator.delete_block(false))
906 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
908 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
911 printf("[S]VPPP\tnext\n");
913 return die_("iterator ended early\n");
914 our_current_position++;
916 printf("S[V]PPP\tnext\n");
918 return die_("iterator ended early\n");
919 our_current_position++;
921 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
922 if(!iterator.delete_block(true))
923 return die_ss_("iterator.delete_block(true)", iterator);
924 our_current_position--;
926 printf("S[V]PPP\tnext\n");
928 return die_("iterator ended early\n");
929 our_current_position++;
931 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
932 if(!iterator.delete_block(false))
933 return die_ss_("iterator.delete_block(false)", iterator);
934 delete_from_our_metadata_(our_current_position--);
936 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
939 printf("S[V]PP\tnext\n");
941 return die_("iterator ended early\n");
942 our_current_position++;
944 printf("SV[P]P\tnext\n");
946 return die_("iterator ended early\n");
947 our_current_position++;
949 printf("SVP[P]\tdelete (last block), replace with padding\n");
950 if(!iterator.delete_block(true))
951 return die_ss_("iterator.delete_block(false)", iterator);
952 our_current_position--;
954 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
957 printf("SV[P]P\tnext\n");
959 return die_("iterator ended early\n");
960 our_current_position++;
962 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
963 if(!iterator.delete_block(false))
964 return die_ss_("iterator.delete_block(false)", iterator);
965 delete_from_our_metadata_(our_current_position--);
967 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
970 printf("SV[P]\tprev\n");
972 return die_("iterator ended early\n");
973 our_current_position--;
975 printf("S[V]P\tprev\n");
977 return die_("iterator ended early\n");
978 our_current_position--;
980 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
981 FLAC__ASSERT(our_current_position == 0);
982 block = iterator.get_block();
983 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
984 FLAC__ASSERT(0 != streaminfo);
985 streaminfo->set_sample_rate(32000);
986 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
987 return die_("copying object");
988 if(!iterator.set_block(block, false))
989 return die_ss_("iterator.set_block(block, false)", iterator);
992 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
995 printf("[S]VP\tnext\n");
997 return die_("iterator ended early\n");
998 our_current_position++;
1000 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1001 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1002 if(!iterator.insert_block_after(app, true))
1003 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1004 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1006 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1008 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1011 printf("SV[A]P\tnext\n");
1012 if(!iterator.next())
1013 return die_("iterator ended early\n");
1014 our_current_position++;
1016 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1017 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1018 if(!iterator.set_block(app, true))
1019 return die_ss_("iterator.set_block(app, true)", iterator);
1020 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1022 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1024 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1027 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1028 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1029 if(!app->set_data(data, sizeof(data), true))
1030 return die_("setting APPLICATION data");
1031 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1032 return die_("copying object");
1033 if(!iterator.set_block(app, false))
1034 return die_ss_("iterator.set_block(app, false)", iterator);
1036 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1039 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1040 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1041 if(!app->set_data(data, 12, true))
1042 return die_("setting APPLICATION data");
1043 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1044 return die_("copying object");
1045 if(!iterator.set_block(app, false))
1046 return die_ss_("iterator.set_block(app, false)", iterator);
1048 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1051 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1052 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1053 if(!app->set_data(data, sizeof(data), true))
1054 return die_("setting APPLICATION data");
1055 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1056 return die_("copying object");
1057 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1058 if(!iterator.set_block(app, true))
1059 return die_ss_("iterator.set_block(app, true)", iterator);
1061 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1064 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1065 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1066 if(!app->set_data(data, 23, true))
1067 return die_("setting APPLICATION data");
1068 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1069 return die_("copying object");
1070 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1071 return die_("copying object");
1072 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1073 if(!iterator.set_block(app, true))
1074 return die_ss_("iterator.set_block(app, true)", iterator);
1076 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1079 printf("SVA[A]PP\tnext\n");
1080 if(!iterator.next())
1081 return die_("iterator ended early\n");
1082 our_current_position++;
1084 printf("SVAA[P]P\tnext\n");
1085 if(!iterator.next())
1086 return die_("iterator ended early\n");
1087 our_current_position++;
1089 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1090 padding->set_length(5);
1091 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1092 return die_("copying object");
1093 if(!iterator.set_block(padding, false))
1094 return die_ss_("iterator.set_block(padding, false)", iterator);
1096 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1099 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1100 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1101 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1102 return die_("copying object");
1103 if(!iterator.set_block(app, false))
1104 return die_ss_("iterator.set_block(app, false)", iterator);
1106 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1109 printf("SVAAP[A]\tset PADDING (equal)\n");
1110 padding->set_length(27);
1111 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1112 return die_("copying object");
1113 if(!iterator.set_block(padding, false))
1114 return die_ss_("iterator.set_block(padding, false)", iterator);
1116 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1119 printf("SVAAP[P]\tprev\n");
1120 if(!iterator.prev())
1121 return die_("iterator ended early\n");
1122 our_current_position--;
1124 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1125 if(!iterator.delete_block(false))
1126 return die_ss_("iterator.delete_block(false)", iterator);
1127 delete_from_our_metadata_(our_current_position--);
1129 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1132 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1133 if(!iterator.delete_block(false))
1134 return die_ss_("iterator.delete_block(false)", iterator);
1135 delete_from_our_metadata_(our_current_position--);
1137 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1140 printf("SV[A]P\tnext\n");
1141 if(!iterator.next())
1142 return die_("iterator ended early\n");
1143 our_current_position++;
1145 printf("SVA[P]\tinsert PADDING after\n");
1146 padding->set_length(5);
1147 if(!iterator.insert_block_after(padding, false))
1148 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1149 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1152 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1155 printf("SVAP[P]\tprev\n");
1156 if(!iterator.prev())
1157 return die_("iterator ended early\n");
1158 our_current_position--;
1160 printf("SVA[P]P\tprev\n");
1161 if(!iterator.prev())
1162 return die_("iterator ended early\n");
1163 our_current_position--;
1165 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1166 if(!app->set_data(data, 32, true))
1167 return die_("setting APPLICATION data");
1168 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1169 return die_("copying object");
1170 if(!iterator.set_block(app, true))
1171 return die_ss_("iterator.set_block(app, true)", iterator);
1173 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1176 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1177 if(!app->set_data(data, 60, true))
1178 return die_("setting APPLICATION data");
1179 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1180 return die_("copying object");
1181 if(!iterator.set_block(app, true))
1182 return die_ss_("iterator.set_block(app, true)", iterator);
1184 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1187 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1188 if(!app->set_data(data, 87, true))
1189 return die_("setting APPLICATION data");
1190 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1191 return die_("copying object");
1192 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1193 if(!iterator.set_block(app, true))
1194 return die_ss_("iterator.set_block(app, true)", iterator);
1196 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1199 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1200 if(!app->set_data(data, 91, true))
1201 return die_("setting APPLICATION data");
1202 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1203 return die_("copying object");
1204 delete_from_our_metadata_(our_current_position+1);
1205 if(!iterator.set_block(app, true))
1206 return die_ss_("iterator.set_block(app, true)", iterator);
1208 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1211 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1212 if(!app->set_data(data, 100, true))
1213 return die_("setting APPLICATION data");
1214 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1215 return die_("copying object");
1216 delete_from_our_metadata_(our_current_position+1);
1217 our_metadata_.blocks[our_current_position]->set_is_last(true);
1218 if(!iterator.set_block(app, true))
1219 return die_ss_("iterator.set_block(app, true)", iterator);
1221 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1224 printf("SV[A]\tset PADDING (equal size)\n");
1225 padding->set_length(app->get_length());
1226 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1227 return die_("copying object");
1228 if(!iterator.set_block(padding, true))
1229 return die_ss_("iterator.set_block(padding, true)", iterator);
1231 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1234 printf("SV[P]\tinsert PADDING after\n");
1235 if(!iterator.insert_block_after(padding, false))
1236 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1237 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1240 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1243 printf("SVP[P]\tinsert PADDING after\n");
1244 padding->set_length(5);
1245 if(!iterator.insert_block_after(padding, false))
1246 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1247 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1250 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1253 printf("SVPP[P]\tprev\n");
1254 if(!iterator.prev())
1255 return die_("iterator ended early\n");
1256 our_current_position--;
1258 printf("SVP[P]P\tprev\n");
1259 if(!iterator.prev())
1260 return die_("iterator ended early\n");
1261 our_current_position--;
1263 printf("SV[P]PP\tprev\n");
1264 if(!iterator.prev())
1265 return die_("iterator ended early\n");
1266 our_current_position--;
1268 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1269 if(!app->set_data(data, 101, true))
1270 return die_("setting APPLICATION data");
1271 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1272 return die_("copying object");
1273 if(!iterator.insert_block_after(app, true))
1274 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1276 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1279 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1280 if(!iterator.delete_block(false))
1281 return die_ss_("iterator.delete_block(false)", iterator);
1282 delete_from_our_metadata_(our_current_position--);
1284 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1287 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1288 if(!app->set_data(data, 97, true))
1289 return die_("setting APPLICATION data");
1290 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1291 return die_("copying object");
1292 if(!iterator.insert_block_after(app, true))
1293 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1295 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1298 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1299 if(!iterator.delete_block(false))
1300 return die_ss_("iterator.delete_block(false)", iterator);
1301 delete_from_our_metadata_(our_current_position--);
1303 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1306 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1307 if(!app->set_data(data, 100, true))
1308 return die_("setting APPLICATION data");
1309 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1310 return die_("copying object");
1311 delete_from_our_metadata_(our_current_position+1);
1312 if(!iterator.insert_block_after(app, true))
1313 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1315 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1318 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1319 if(!iterator.delete_block(false))
1320 return die_ss_("iterator.delete_block(false)", iterator);
1321 delete_from_our_metadata_(our_current_position--);
1323 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1326 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1327 if(!app->set_data(data, 96, true))
1328 return die_("setting APPLICATION data");
1329 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1330 return die_("copying object");
1331 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1332 if(!iterator.insert_block_after(app, true))
1333 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1335 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1338 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1339 if(!iterator.delete_block(false))
1340 return die_ss_("iterator.delete_block(false)", iterator);
1341 delete_from_our_metadata_(our_current_position--);
1343 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1346 printf("S[V]PP\tnext\n");
1347 if(!iterator.next())
1348 return die_("iterator ended early\n");
1349 our_current_position++;
1351 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1352 if(!iterator.delete_block(false))
1353 return die_ss_("iterator.delete_block(false)", iterator);
1354 delete_from_our_metadata_(our_current_position--);
1356 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1359 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1360 if(!app->set_data(data, 1, true))
1361 return die_("setting APPLICATION data");
1362 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1363 return die_("copying object");
1364 delete_from_our_metadata_(our_current_position+1);
1365 if(!iterator.insert_block_after(app, true))
1366 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1368 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1375 if(!remove_file_(flacfile_))
1381 static bool test_level_2_(bool filename_based)
1383 FLAC::Metadata::Prototype *block;
1384 FLAC::Metadata::StreamInfo *streaminfo;
1385 FLAC::Metadata::Application *app;
1386 FLAC::Metadata::Padding *padding;
1387 FLAC__byte data[2000];
1388 unsigned our_current_position;
1390 // initialize 'data' to avoid Valgrind errors
1391 memset(data, 0, sizeof(data));
1393 printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1395 printf("generate read-only file\n");
1397 if(!generate_file_(/*include_cuesheet=*/false))
1400 if(!change_stats_(flacfile_, /*read_only=*/true))
1403 printf("create chain\n");
1404 FLAC::Metadata::Chain chain;
1405 if(!chain.is_valid())
1406 return die_("allocating memory for chain");
1408 printf("read chain\n");
1410 if(!read_chain_(chain, flacfile_, filename_based))
1411 return die_c_("reading chain", chain.status());
1413 printf("[S]VP\ttest initial metadata\n");
1415 if(!compare_chain_(chain, 0, 0))
1417 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1420 printf("switch file to read-write\n");
1422 if(!change_stats_(flacfile_, /*read-only=*/false))
1425 printf("create iterator\n");
1427 FLAC::Metadata::Iterator iterator;
1428 if(!iterator.is_valid())
1429 return die_("allocating memory for iterator");
1431 our_current_position = 0;
1433 iterator.init(chain);
1435 if(0 == (block = iterator.get_block()))
1436 return die_("getting block from iterator");
1438 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1440 printf("[S]VP\tmodify STREAMINFO, write\n");
1442 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1443 FLAC__ASSERT(0 != streaminfo);
1444 streaminfo->set_sample_rate(32000);
1445 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1446 return die_("copying object");
1449 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1450 return die_c_("during chain.write(false, true)", chain.status());
1451 block = iterator.get_block();
1452 if(!compare_chain_(chain, our_current_position, block))
1455 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1458 printf("[S]VP\tnext\n");
1459 if(!iterator.next())
1460 return die_("iterator ended early\n");
1461 our_current_position++;
1463 printf("S[V]P\tnext\n");
1464 if(!iterator.next())
1465 return die_("iterator ended early\n");
1466 our_current_position++;
1468 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1469 if(0 == (block = iterator.get_block()))
1470 return die_("getting block from iterator");
1471 if(0 == (app = new FLAC::Metadata::Application()))
1472 return die_("new FLAC::Metadata::Application()");
1473 app->set_id((const unsigned char *)"duh");
1474 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1475 return die_("setting APPLICATION data");
1477 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1478 return die_("copying object");
1479 if(!iterator.set_block(app))
1480 return die_c_("iterator.set_block(app)", chain.status());
1482 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1483 return die_c_("during chain.write(false, false)", chain.status());
1484 block = iterator.get_block();
1485 if(!compare_chain_(chain, our_current_position, block))
1488 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1491 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1492 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1493 return die_("copying object");
1494 if(!app->set_data(data, 26, true))
1495 return die_("setting APPLICATION data");
1496 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1497 return die_("copying object");
1498 if(!iterator.set_block(app))
1499 return die_c_("iterator.set_block(app)", chain.status());
1501 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1502 return die_c_("during chain.write(false, false)", chain.status());
1503 block = iterator.get_block();
1504 if(!compare_chain_(chain, our_current_position, block))
1507 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1510 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1511 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1512 return die_("copying object");
1513 if(!app->set_data(data, 28, true))
1514 return die_("setting APPLICATION data");
1515 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1516 return die_("copying object");
1517 if(!iterator.set_block(app))
1518 return die_c_("iterator.set_block(app)", chain.status());
1520 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1521 return die_c_("during chain.write(false, false)", chain.status());
1522 block = iterator.get_block();
1523 if(!compare_chain_(chain, our_current_position, block))
1526 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1529 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1530 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1531 return die_("copying object");
1532 if(!app->set_data(data, 36, true))
1533 return die_("setting APPLICATION data");
1534 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1535 return die_("copying object");
1536 if(!iterator.set_block(app))
1537 return die_c_("iterator.set_block(app)", chain.status());
1539 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1540 return die_c_("during chain.write(false, false)", chain.status());
1541 block = iterator.get_block();
1542 if(!compare_chain_(chain, our_current_position, block))
1545 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1548 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1549 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1550 return die_("copying object");
1551 if(!app->set_data(data, 33, true))
1552 return die_("setting APPLICATION data");
1553 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1554 return die_("copying object");
1555 if(!iterator.set_block(app))
1556 return die_c_("iterator.set_block(app)", chain.status());
1558 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1559 return die_c_("during chain.write(true, false)", chain.status());
1560 block = iterator.get_block();
1561 if(!compare_chain_(chain, our_current_position, block))
1564 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1567 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1568 if(0 == (padding = new FLAC::Metadata::Padding()))
1569 return die_("creating PADDING block");
1570 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1571 return die_("copying object");
1572 if(!app->set_data(data, 29, true))
1573 return die_("setting APPLICATION data");
1574 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1575 return die_("copying object");
1576 padding->set_length(0);
1577 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1578 return die_("internal error");
1579 if(!iterator.set_block(app))
1580 return die_c_("iterator.set_block(app)", chain.status());
1582 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1583 return die_c_("during chain.write(true, false)", chain.status());
1584 block = iterator.get_block();
1585 if(!compare_chain_(chain, our_current_position, block))
1588 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1591 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1592 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1593 return die_("copying object");
1594 if(!app->set_data(data, 16, true))
1595 return die_("setting APPLICATION data");
1596 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1597 return die_("copying object");
1598 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1599 if(!iterator.set_block(app))
1600 return die_c_("iterator.set_block(app)", chain.status());
1602 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1603 return die_c_("during chain.write(true, false)", chain.status());
1604 block = iterator.get_block();
1605 if(!compare_chain_(chain, our_current_position, block))
1608 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1611 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\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, 50, 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=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1622 return die_c_("during chain.write(true, false)", chain.status());
1623 block = iterator.get_block();
1624 if(!compare_chain_(chain, our_current_position, block))
1627 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1630 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\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, 56, 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 add_to_padding_length_(our_current_position+1, -(56 - 50));
1638 if(!iterator.set_block(app))
1639 return die_c_("iterator.set_block(app)", chain.status());
1641 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1642 return die_c_("during chain.write(true, false)", chain.status());
1643 block = iterator.get_block();
1644 if(!compare_chain_(chain, our_current_position, block))
1647 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1650 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1651 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1652 return die_("copying object");
1653 if(!app->set_data(data, 67, true))
1654 return die_("setting APPLICATION data");
1655 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1656 return die_("copying object");
1657 delete_from_our_metadata_(our_current_position+1);
1658 if(!iterator.set_block(app))
1659 return die_c_("iterator.set_block(app)", chain.status());
1661 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1662 return die_c_("during chain.write(true, false)", chain.status());
1663 block = iterator.get_block();
1664 if(!compare_chain_(chain, our_current_position, block))
1667 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1670 printf("SV[A]\tprev\n");
1671 if(!iterator.prev())
1672 return die_("iterator ended early\n");
1673 our_current_position--;
1675 printf("S[V]A\tprev\n");
1676 if(!iterator.prev())
1677 return die_("iterator ended early\n");
1678 our_current_position--;
1680 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1681 if(0 == (padding = new FLAC::Metadata::Padding()))
1682 return die_("creating PADDING block");
1683 padding->set_length(30);
1684 if(!iterator.insert_block_before(padding))
1685 printf("\titerator.insert_block_before() returned false like it should\n");
1687 return die_("iterator.insert_block_before() should have returned false");
1689 printf("[S]VA\tnext\n");
1690 if(!iterator.next())
1691 return die_("iterator ended early\n");
1692 our_current_position++;
1694 printf("S[V]A\tinsert PADDING after\n");
1695 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1696 return die_("copying metadata");
1697 if(!iterator.insert_block_after(padding))
1698 return die_("iterator.insert_block_after(padding)");
1700 block = iterator.get_block();
1701 if(!compare_chain_(chain, our_current_position, block))
1705 printf("SV[P]A\tinsert PADDING before\n");
1706 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1707 return die_("creating PADDING block");
1708 padding->set_length(17);
1709 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1710 return die_("copying metadata");
1711 if(!iterator.insert_block_before(padding))
1712 return die_("iterator.insert_block_before(padding)");
1714 block = iterator.get_block();
1715 if(!compare_chain_(chain, our_current_position, block))
1719 printf("SV[P]PA\tinsert PADDING before\n");
1720 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1721 return die_("creating PADDING block");
1722 padding->set_length(0);
1723 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1724 return die_("copying metadata");
1725 if(!iterator.insert_block_before(padding))
1726 return die_("iterator.insert_block_before(padding)");
1728 block = iterator.get_block();
1729 if(!compare_chain_(chain, our_current_position, block))
1733 printf("SV[P]PPA\tnext\n");
1734 if(!iterator.next())
1735 return die_("iterator ended early\n");
1736 our_current_position++;
1738 printf("SVP[P]PA\tnext\n");
1739 if(!iterator.next())
1740 return die_("iterator ended early\n");
1741 our_current_position++;
1743 printf("SVPP[P]A\tnext\n");
1744 if(!iterator.next())
1745 return die_("iterator ended early\n");
1746 our_current_position++;
1748 printf("SVPPP[A]\tinsert PADDING after\n");
1749 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1750 return die_("creating PADDING block");
1751 padding->set_length(57);
1752 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1753 return die_("copying metadata");
1754 if(!iterator.insert_block_after(padding))
1755 return die_("iterator.insert_block_after(padding)");
1757 block = iterator.get_block();
1758 if(!compare_chain_(chain, our_current_position, block))
1762 printf("SVPPPA[P]\tinsert PADDING before\n");
1763 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1764 return die_("creating PADDING block");
1765 padding->set_length(99);
1766 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1767 return die_("copying metadata");
1768 if(!iterator.insert_block_before(padding))
1769 return die_("iterator.insert_block_before(padding)");
1771 block = iterator.get_block();
1772 if(!compare_chain_(chain, our_current_position, block))
1777 our_current_position = 0;
1779 printf("SVPPPAPP\tmerge padding\n");
1780 chain.merge_padding();
1781 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1782 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1783 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1784 delete_from_our_metadata_(7);
1785 delete_from_our_metadata_(4);
1786 delete_from_our_metadata_(3);
1788 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1789 return die_c_("during chain.write(true, false)", chain.status());
1790 if(!compare_chain_(chain, 0, 0))
1792 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1795 printf("SVPAP\tsort padding\n");
1796 chain.sort_padding();
1797 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1798 delete_from_our_metadata_(2);
1800 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1801 return die_c_("during chain.write(true, false)", chain.status());
1802 if(!compare_chain_(chain, 0, 0))
1804 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1807 printf("create iterator\n");
1809 FLAC::Metadata::Iterator iterator;
1810 if(!iterator.is_valid())
1811 return die_("allocating memory for iterator");
1813 our_current_position = 0;
1815 iterator.init(chain);
1817 printf("[S]VAP\tnext\n");
1818 if(!iterator.next())
1819 return die_("iterator ended early\n");
1820 our_current_position++;
1822 printf("S[V]AP\tnext\n");
1823 if(!iterator.next())
1824 return die_("iterator ended early\n");
1825 our_current_position++;
1827 printf("SV[A]P\tdelete middle block, replace with padding\n");
1828 if(0 == (padding = new FLAC::Metadata::Padding()))
1829 return die_("creating PADDING block");
1830 padding->set_length(71);
1831 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1832 return die_("copying object");
1833 if(!iterator.delete_block(/*replace_with_padding=*/true))
1834 return die_c_("iterator.delete_block(true)", chain.status());
1836 block = iterator.get_block();
1837 if(!compare_chain_(chain, our_current_position, block))
1841 printf("S[V]PP\tnext\n");
1842 if(!iterator.next())
1843 return die_("iterator ended early\n");
1844 our_current_position++;
1846 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1847 delete_from_our_metadata_(our_current_position--);
1848 if(!iterator.delete_block(/*replace_with_padding=*/false))
1849 return die_c_("iterator.delete_block(false)", chain.status());
1851 block = iterator.get_block();
1852 if(!compare_chain_(chain, our_current_position, block))
1856 printf("S[V]P\tnext\n");
1857 if(!iterator.next())
1858 return die_("iterator ended early\n");
1859 our_current_position++;
1861 printf("SV[P]\tdelete last block, replace with padding\n");
1862 if(0 == (padding = new FLAC::Metadata::Padding()))
1863 return die_("creating PADDING block");
1864 padding->set_length(219);
1865 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1866 return die_("copying object");
1867 if(!iterator.delete_block(/*replace_with_padding=*/true))
1868 return die_c_("iterator.delete_block(true)", chain.status());
1870 block = iterator.get_block();
1871 if(!compare_chain_(chain, our_current_position, block))
1875 printf("S[V]P\tnext\n");
1876 if(!iterator.next())
1877 return die_("iterator ended early\n");
1878 our_current_position++;
1880 printf("SV[P]\tdelete last block, don't replace with padding\n");
1881 delete_from_our_metadata_(our_current_position--);
1882 if(!iterator.delete_block(/*replace_with_padding=*/false))
1883 return die_c_("iterator.delete_block(false)", chain.status());
1885 block = iterator.get_block();
1886 if(!compare_chain_(chain, our_current_position, block))
1890 printf("S[V]\tprev\n");
1891 if(!iterator.prev())
1892 return die_("iterator ended early\n");
1893 our_current_position--;
1895 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1896 if(iterator.delete_block(/*replace_with_padding=*/false))
1897 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1899 block = iterator.get_block();
1900 if(!compare_chain_(chain, our_current_position, block))
1904 } // delete iterator
1905 our_current_position = 0;
1907 printf("SV\tmerge padding\n");
1908 chain.merge_padding();
1910 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1911 return die_c_("during chain.write(false, false)", chain.status());
1912 if(!compare_chain_(chain, 0, 0))
1914 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1917 printf("SV\tsort padding\n");
1918 chain.sort_padding();
1920 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1921 return die_c_("during chain.write(false, false)", chain.status());
1922 if(!compare_chain_(chain, 0, 0))
1924 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1927 if(!remove_file_(flacfile_))
1933 static bool test_level_2_misc_()
1935 ::FLAC__IOCallbacks callbacks;
1937 memset(&callbacks, 0, sizeof(callbacks));
1938 callbacks.read = (::FLAC__IOCallback_Read)fread;
1939 #ifdef FLAC__VALGRIND_TESTING
1940 callbacks.write = chain_write_cb_;
1942 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
1944 callbacks.seek = chain_seek_cb_;
1945 callbacks.tell = chain_tell_cb_;
1946 callbacks.eof = chain_eof_cb_;
1948 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1950 printf("generate file\n");
1952 if(!generate_file_(/*include_cuesheet=*/false))
1955 printf("create chain\n");
1956 FLAC::Metadata::Chain chain;
1957 if(!chain.is_valid())
1958 return die_("allocating chain");
1960 printf("read chain (filename-based)\n");
1962 if(!chain.read(flacfile_))
1963 return die_c_("reading chain", chain.status());
1965 printf("write chain with wrong method Chain::write(with callbacks)\n");
1967 if(chain.write(/*use_padding=*/false, 0, callbacks))
1968 return die_c_("mismatched write should have failed", chain.status());
1969 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1970 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
1971 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1974 printf("read chain (filename-based)\n");
1976 if(!chain.read(flacfile_))
1977 return die_c_("reading chain", chain.status());
1979 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
1981 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
1982 return die_c_("mismatched write should have failed", chain.status());
1983 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1984 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
1985 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1988 printf("read chain (callback-based)\n");
1990 FILE *file = fopen(flacfile_, "rb");
1992 return die_("opening file");
1993 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
1995 return die_c_("reading chain", chain.status());
2000 printf("write chain with wrong method write()\n");
2002 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2003 return die_c_("mismatched write should have failed", chain.status());
2004 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2005 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2006 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2009 printf("read chain (callback-based)\n");
2011 FILE *file = fopen(flacfile_, "rb");
2013 return die_("opening file");
2014 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2016 return die_c_("reading chain", chain.status());
2021 printf("testing Chain::check_if_tempfile_needed()... ");
2023 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2024 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2026 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2028 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2030 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2031 return die_c_("mismatched write should have failed", chain.status());
2032 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2033 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2034 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2037 printf("read chain (callback-based)\n");
2039 FILE *file = fopen(flacfile_, "rb");
2041 return die_("opening file");
2042 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2044 return die_c_("reading chain", chain.status());
2049 printf("create iterator\n");
2051 FLAC::Metadata::Iterator iterator;
2052 if(!iterator.is_valid())
2053 return die_("allocating memory for iterator");
2055 iterator.init(chain);
2057 printf("[S]VP\tnext\n");
2058 if(!iterator.next())
2059 return die_("iterator ended early\n");
2061 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2062 if(!iterator.delete_block(/*replace_with_padding=*/false))
2063 return die_c_("block delete failed\n", chain.status());
2065 printf("testing Chain::check_if_tempfile_needed()... ");
2067 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2068 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2070 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2072 printf("write chain with wrong method Chain::write(with callbacks)\n");
2074 if(chain.write(/*use_padding=*/false, 0, callbacks))
2075 return die_c_("mismatched write should have failed", chain.status());
2076 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2077 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2078 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2081 } // delete iterator
2083 if(!remove_file_(flacfile_))
2089 bool test_metadata_file_manipulation()
2091 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2093 our_metadata_.num_blocks = 0;
2095 if(!test_level_0_())
2098 if(!test_level_1_())
2101 if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2103 if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2105 if(!test_level_2_misc_())