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 if(unlink(filename) < 0) {
228 cleanup_tempfile_(tempfile, tempfilename);
233 if(0 != rename(*tempfilename, filename)) {
234 cleanup_tempfile_(tempfile, tempfilename);
238 cleanup_tempfile_(tempfile, tempfilename);
243 bool get_file_stats_(const char *filename, struct stat *stats)
245 FLAC__ASSERT(0 != filename);
246 FLAC__ASSERT(0 != stats);
247 return (0 == stat(filename, stats));
250 void set_file_stats_(const char *filename, struct stat *stats)
252 struct utimbuf srctime;
254 FLAC__ASSERT(0 != filename);
255 FLAC__ASSERT(0 != stats);
257 srctime.actime = stats->st_atime;
258 srctime.modtime = stats->st_mtime;
259 (void)chmod(filename, stats->st_mode);
260 (void)utime(filename, &srctime);
261 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
262 (void)chown(filename, stats->st_uid, (gid_t)(-1));
263 (void)chown(filename, (uid_t)(-1), stats->st_gid);
267 #ifdef FLAC__VALGRIND_TESTING
268 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
270 FILE *stream = (FILE*)handle;
271 size_t ret = fwrite(ptr, size, nmemb, stream);
278 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
280 off_t o = (off_t)offset;
281 FLAC__ASSERT(offset == o);
282 return fseeko((FILE*)handle, o, whence);
285 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
287 return ftello((FILE*)handle);
290 static int chain_eof_cb_(::FLAC__IOHandle handle)
292 return feof((FILE*)handle);
295 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
298 return chain.write(use_padding, preserve_file_stats);
300 ::FLAC__IOCallbacks callbacks;
302 memset(&callbacks, 0, sizeof(callbacks));
303 callbacks.read = (::FLAC__IOCallback_Read)fread;
304 #ifdef FLAC__VALGRIND_TESTING
305 callbacks.write = chain_write_cb_;
307 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
309 callbacks.seek = chain_seek_cb_;
310 callbacks.eof = chain_eof_cb_;
312 if(chain.check_if_tempfile_needed(use_padding)) {
314 FILE *file, *tempfile;
316 if(preserve_file_stats) {
317 if(!get_file_stats_(filename, &stats))
320 if(0 == (file = fopen(filename, "rb")))
321 return false; /*@@@ chain status still says OK though */
322 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
324 cleanup_tempfile_(&tempfile, &tempfilename);
325 return false; /*@@@ chain status still says OK though */
327 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
335 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
337 if(preserve_file_stats)
338 set_file_stats_(filename, &stats);
341 FILE *file = fopen(filename, "r+b");
343 return false; /*@@@ chain status still says OK though */
344 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
353 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
356 return chain.read(filename);
358 ::FLAC__IOCallbacks callbacks;
360 memset(&callbacks, 0, sizeof(callbacks));
361 callbacks.read = (::FLAC__IOCallback_Read)fread;
362 callbacks.seek = chain_seek_cb_;
363 callbacks.tell = chain_tell_cb_;
367 FILE *file = fopen(filename, "rb");
369 return false; /*@@@ chain status still says OK though */
370 ret = chain.read((::FLAC__IOHandle)file, callbacks);
377 /* function for comparing our metadata to a FLAC::Metadata::Chain */
379 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
382 FLAC::Metadata::Iterator iterator;
385 printf("\tcomparing chain... ");
388 if(!iterator.is_valid())
389 return die_("allocating memory for iterator");
391 iterator.init(chain);
395 FLAC::Metadata::Prototype *block;
400 if(0 == (block = iterator.get_block()))
401 return die_("getting block from iterator");
403 if(*block != *our_metadata_.blocks[i])
404 return die_("metadata block mismatch");
408 next_ok = iterator.next();
409 } while(i < our_metadata_.num_blocks && next_ok);
412 return die_("chain has more blocks than expected");
414 if(i < our_metadata_.num_blocks)
415 return die_("short block count in chain");
417 if(0 != current_block) {
418 printf("CURRENT_POSITION... ");
421 if(*current_block != *our_metadata_.blocks[current_position])
422 return die_("metadata block mismatch");
430 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
435 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
436 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
438 printf("content... ");
442 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
445 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
447 /* don't bother checking if we've already hit an error */
451 printf("%d... ", mc_our_block_number_);
454 if(!ignore_metadata_) {
455 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
456 (void)die_("got more metadata blocks than expected");
457 error_occurred_ = true;
460 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
461 (void)die_("metadata block mismatch");
462 error_occurred_ = true;
467 mc_our_block_number_++;
470 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
472 error_occurred_ = true;
473 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
476 static bool generate_file_(FLAC__bool include_cuesheet)
478 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
479 ::FLAC__StreamMetadata *metadata[3];
480 unsigned i = 0, n = 0;
482 printf("generating FLAC file for test\n");
484 while(our_metadata_.num_blocks > 0)
485 delete_from_our_metadata_(0);
487 streaminfo.is_last = false;
488 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
489 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
490 streaminfo.data.stream_info.min_blocksize = 576;
491 streaminfo.data.stream_info.max_blocksize = 576;
492 streaminfo.data.stream_info.min_framesize = 0;
493 streaminfo.data.stream_info.max_framesize = 0;
494 streaminfo.data.stream_info.sample_rate = 44100;
495 streaminfo.data.stream_info.channels = 1;
496 streaminfo.data.stream_info.bits_per_sample = 8;
497 streaminfo.data.stream_info.total_samples = 0;
498 memset(streaminfo.data.stream_info.md5sum, 0, 16);
501 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
502 vorbiscomment.is_last = false;
503 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
504 vorbiscomment.length = (4 + vendor_string_length) + 4;
505 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
506 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
507 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
508 vorbiscomment.data.vorbis_comment.num_comments = 0;
509 vorbiscomment.data.vorbis_comment.comments = 0;
513 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
514 return die_("priming our metadata");
515 cuesheet->is_last = false;
516 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
517 cuesheet->data.cue_sheet.lead_in = 123;
518 cuesheet->data.cue_sheet.is_cd = false;
519 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
520 return die_("priming our metadata");
521 cuesheet->data.cue_sheet.tracks[0].number = 1;
522 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
523 return die_("priming our metadata");
526 padding.is_last = true;
527 padding.type = ::FLAC__METADATA_TYPE_PADDING;
528 padding.length = 1234;
530 metadata[n++] = &vorbiscomment;
531 if (include_cuesheet)
532 metadata[n++] = cuesheet;
533 metadata[n++] = &padding;
535 FLAC::Metadata::StreamInfo s(&streaminfo);
536 FLAC::Metadata::VorbisComment v(&vorbiscomment);
537 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
538 FLAC::Metadata::Padding p(&padding);
540 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
541 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
542 (include_cuesheet && !insert_to_our_metadata_(&v, i++, /*copy=*/true)) ||
543 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
545 return die_("priming our metadata");
547 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
548 return die_("creating the encoded file");
550 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
555 static bool test_file_(const char *filename, bool ignore_metadata)
557 OurFileDecoder decoder(ignore_metadata);
559 FLAC__ASSERT(0 != filename);
561 mc_our_block_number_ = 0;
562 decoder.error_occurred_ = false;
564 printf("\ttesting '%s'... ", filename);
567 if(!decoder.is_valid())
568 return die_("couldn't allocate decoder instance");
570 decoder.set_md5_checking(true);
571 decoder.set_metadata_respond_all();
572 if(decoder.init(filename) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
574 return die_("initializing decoder\n");
576 if(!decoder.process_until_end_of_stream()) {
578 return die_("decoding file\n");
583 if(decoder.error_occurred_)
586 if(mc_our_block_number_ != our_metadata_.num_blocks)
587 return die_("short metadata block count");
593 static bool change_stats_(const char *filename, bool read_only)
595 if(!grabbag__file_change_stats(filename, read_only))
596 return die_("during grabbag__file_change_stats()");
601 static bool remove_file_(const char *filename)
603 while(our_metadata_.num_blocks > 0)
604 delete_from_our_metadata_(0);
606 if(!grabbag__file_remove_file(filename))
607 return die_("removing file");
612 static bool test_level_0_()
614 FLAC::Metadata::StreamInfo streaminfo;
616 printf("\n\n++++++ testing level 0 interface\n");
618 if(!generate_file_(/*include_cuesheet=*/true))
621 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
624 printf("testing FLAC::Metadata::get_streaminfo()... ");
626 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
627 return die_("during FLAC::Metadata::get_streaminfo()");
629 /* check to see if some basic data matches (c.f. generate_file_()) */
630 if(streaminfo.get_channels() != 1)
631 return die_("mismatch in streaminfo.get_channels()");
632 if(streaminfo.get_bits_per_sample() != 8)
633 return die_("mismatch in streaminfo.get_bits_per_sample()");
634 if(streaminfo.get_sample_rate() != 44100)
635 return die_("mismatch in streaminfo.get_sample_rate()");
636 if(streaminfo.get_min_blocksize() != 576)
637 return die_("mismatch in streaminfo.get_min_blocksize()");
638 if(streaminfo.get_max_blocksize() != 576)
639 return die_("mismatch in streaminfo.get_max_blocksize()");
644 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
646 FLAC::Metadata::VorbisComment *tags = 0;
648 if(!FLAC::Metadata::get_tags(flacfile_, tags))
649 return die_("during FLAC::Metadata::get_tags()");
651 /* check to see if some basic data matches (c.f. generate_file_()) */
652 if(tags->get_num_comments() != 0)
653 return die_("mismatch in tags->get_num_comments()");
661 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
663 FLAC::Metadata::VorbisComment tags;
665 if(!FLAC::Metadata::get_tags(flacfile_, tags))
666 return die_("during FLAC::Metadata::get_tags()");
668 /* check to see if some basic data matches (c.f. generate_file_()) */
669 if(tags.get_num_comments() != 0)
670 return die_("mismatch in tags.get_num_comments()");
676 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
678 FLAC::Metadata::CueSheet *cuesheet = 0;
680 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
681 return die_("during FLAC::Metadata::get_cuesheet()");
683 /* check to see if some basic data matches (c.f. generate_file_()) */
684 if(cuesheet->get_lead_in() != 123)
685 return die_("mismatch in cuesheet->get_lead_in()");
693 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
695 FLAC::Metadata::CueSheet cuesheet;
697 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
698 return die_("during FLAC::Metadata::get_cuesheet()");
700 /* check to see if some basic data matches (c.f. generate_file_()) */
701 if(cuesheet.get_lead_in() != 123)
702 return die_("mismatch in cuesheet.get_lead_in()");
707 if(!remove_file_(flacfile_))
713 static bool test_level_1_()
715 FLAC::Metadata::Prototype *block;
716 FLAC::Metadata::StreamInfo *streaminfo;
717 FLAC::Metadata::Padding *padding;
718 FLAC::Metadata::Application *app;
719 FLAC__byte data[1000];
720 unsigned our_current_position = 0;
722 // initialize 'data' to avoid Valgrind errors
723 memset(data, 0, sizeof(data));
725 printf("\n\n++++++ testing level 1 interface\n");
727 /************************************************************/
729 printf("simple iterator on read-only file\n");
731 if(!generate_file_(/*include_cuesheet=*/false))
734 if(!change_stats_(flacfile_, /*read_only=*/true))
737 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
740 FLAC::Metadata::SimpleIterator iterator;
742 if(!iterator.is_valid())
743 return die_("iterator.is_valid() returned false");
745 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
746 return die_("iterator.init() returned false");
748 printf("is writable = %u\n", (unsigned)iterator.is_writable());
749 if(iterator.is_writable())
750 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
752 printf("iterate forwards\n");
754 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
755 return die_("expected STREAMINFO type from iterator.get_block_type()");
756 if(0 == (block = iterator.get_block()))
757 return die_("getting block 0");
758 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
759 return die_("expected STREAMINFO type");
760 if(block->get_is_last())
761 return die_("expected is_last to be false");
762 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
763 return die_("bad STREAMINFO length");
764 /* check to see if some basic data matches (c.f. generate_file_()) */
765 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
766 FLAC__ASSERT(0 != streaminfo);
767 if(streaminfo->get_channels() != 1)
768 return die_("mismatch in channels");
769 if(streaminfo->get_bits_per_sample() != 8)
770 return die_("mismatch in bits_per_sample");
771 if(streaminfo->get_sample_rate() != 44100)
772 return die_("mismatch in sample_rate");
773 if(streaminfo->get_min_blocksize() != 576)
774 return die_("mismatch in min_blocksize");
775 if(streaminfo->get_max_blocksize() != 576)
776 return die_("mismatch in max_blocksize");
777 // we will delete streaminfo a little later when we're really done with it...
780 return die_("forward iterator ended early");
781 our_current_position++;
784 return die_("forward iterator ended early");
785 our_current_position++;
787 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
788 return die_("expected PADDING type from iterator.get_block_type()");
789 if(0 == (block = iterator.get_block()))
790 return die_("getting block 1");
791 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
792 return die_("expected PADDING type");
793 if(!block->get_is_last())
794 return die_("expected is_last to be true");
795 /* check to see if some basic data matches (c.f. generate_file_()) */
796 if(block->get_length() != 1234)
797 return die_("bad PADDING length");
801 return die_("forward iterator returned true but should have returned false");
803 printf("iterate backwards\n");
805 return die_("reverse iterator ended early");
807 return die_("reverse iterator ended early");
809 return die_("reverse iterator returned true but should have returned false");
811 printf("testing iterator.set_block() on read-only file...\n");
813 if(!iterator.set_block(streaminfo, false))
814 printf("PASSED. iterator.set_block() returned false like it should\n");
816 return die_("iterator.set_block() returned true but shouldn't have");
820 /************************************************************/
822 printf("simple iterator on writable file\n");
824 if(!change_stats_(flacfile_, /*read-only=*/false))
827 printf("creating APPLICATION block\n");
829 if(0 == (app = new FLAC::Metadata::Application()))
830 return die_("new FLAC::Metadata::Application()");
831 app->set_id((const unsigned char *)"duh");
833 printf("creating PADDING block\n");
835 if(0 == (padding = new FLAC::Metadata::Padding()))
836 return die_("new FLAC::Metadata::Padding()");
837 padding->set_length(20);
839 FLAC::Metadata::SimpleIterator iterator;
841 if(!iterator.is_valid())
842 return die_("iterator.is_valid() returned false");
844 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
845 return die_("iterator.init() returned false");
846 our_current_position = 0;
848 printf("is writable = %u\n", (unsigned)iterator.is_writable());
850 printf("[S]VP\ttry to write over STREAMINFO block...\n");
851 if(!iterator.set_block(app, false))
852 printf("\titerator.set_block() returned false like it should\n");
854 return die_("iterator.set_block() returned true but shouldn't have");
856 printf("[S]VP\tnext\n");
858 return die_("iterator ended early\n");
859 our_current_position++;
861 printf("S[V]P\tnext\n");
863 return die_("iterator ended early\n");
864 our_current_position++;
866 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
867 padding->set_length(25);
868 if(!iterator.insert_block_after(padding, false))
869 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
870 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
873 printf("SVP[P]\tprev\n");
875 return die_("iterator ended early\n");
876 our_current_position--;
878 printf("SV[P]P\tprev\n");
880 return die_("iterator ended early\n");
881 our_current_position--;
883 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
884 padding->set_length(30);
885 if(!iterator.insert_block_after(padding, false))
886 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
887 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
890 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
893 printf("SV[P]PP\tprev\n");
895 return die_("iterator ended early\n");
896 our_current_position--;
898 printf("S[V]PPP\tprev\n");
900 return die_("iterator ended early\n");
901 our_current_position--;
903 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
904 if(iterator.delete_block(false))
905 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
907 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
910 printf("[S]VPPP\tnext\n");
912 return die_("iterator ended early\n");
913 our_current_position++;
915 printf("S[V]PPP\tnext\n");
917 return die_("iterator ended early\n");
918 our_current_position++;
920 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
921 if(!iterator.delete_block(true))
922 return die_ss_("iterator.delete_block(true)", iterator);
923 our_current_position--;
925 printf("S[V]PPP\tnext\n");
927 return die_("iterator ended early\n");
928 our_current_position++;
930 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
931 if(!iterator.delete_block(false))
932 return die_ss_("iterator.delete_block(false)", iterator);
933 delete_from_our_metadata_(our_current_position--);
935 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
938 printf("S[V]PP\tnext\n");
940 return die_("iterator ended early\n");
941 our_current_position++;
943 printf("SV[P]P\tnext\n");
945 return die_("iterator ended early\n");
946 our_current_position++;
948 printf("SVP[P]\tdelete (last block), replace with padding\n");
949 if(!iterator.delete_block(true))
950 return die_ss_("iterator.delete_block(false)", iterator);
951 our_current_position--;
953 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
956 printf("SV[P]P\tnext\n");
958 return die_("iterator ended early\n");
959 our_current_position++;
961 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
962 if(!iterator.delete_block(false))
963 return die_ss_("iterator.delete_block(false)", iterator);
964 delete_from_our_metadata_(our_current_position--);
966 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
969 printf("SV[P]\tprev\n");
971 return die_("iterator ended early\n");
972 our_current_position--;
974 printf("S[V]P\tprev\n");
976 return die_("iterator ended early\n");
977 our_current_position--;
979 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
980 FLAC__ASSERT(our_current_position == 0);
981 block = iterator.get_block();
982 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
983 FLAC__ASSERT(0 != streaminfo);
984 streaminfo->set_sample_rate(32000);
985 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
986 return die_("copying object");
987 if(!iterator.set_block(block, false))
988 return die_ss_("iterator.set_block(block, false)", iterator);
991 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
994 printf("[S]VP\tnext\n");
996 return die_("iterator ended early\n");
997 our_current_position++;
999 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1000 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1001 if(!iterator.insert_block_after(app, true))
1002 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1003 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1005 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1007 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1010 printf("SV[A]P\tnext\n");
1011 if(!iterator.next())
1012 return die_("iterator ended early\n");
1013 our_current_position++;
1015 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1016 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1017 if(!iterator.set_block(app, true))
1018 return die_ss_("iterator.set_block(app, true)", iterator);
1019 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1021 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1023 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1026 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1027 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1028 if(!app->set_data(data, sizeof(data), true))
1029 return die_("setting APPLICATION data");
1030 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1031 return die_("copying object");
1032 if(!iterator.set_block(app, false))
1033 return die_ss_("iterator.set_block(app, false)", iterator);
1035 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1038 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1039 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1040 if(!app->set_data(data, 12, true))
1041 return die_("setting APPLICATION data");
1042 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1043 return die_("copying object");
1044 if(!iterator.set_block(app, false))
1045 return die_ss_("iterator.set_block(app, false)", iterator);
1047 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1050 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1051 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1052 if(!app->set_data(data, sizeof(data), true))
1053 return die_("setting APPLICATION data");
1054 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1055 return die_("copying object");
1056 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1057 if(!iterator.set_block(app, true))
1058 return die_ss_("iterator.set_block(app, true)", iterator);
1060 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1063 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1064 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1065 if(!app->set_data(data, 23, true))
1066 return die_("setting APPLICATION data");
1067 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1068 return die_("copying object");
1069 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1070 return die_("copying object");
1071 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1072 if(!iterator.set_block(app, true))
1073 return die_ss_("iterator.set_block(app, true)", iterator);
1075 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1078 printf("SVA[A]PP\tnext\n");
1079 if(!iterator.next())
1080 return die_("iterator ended early\n");
1081 our_current_position++;
1083 printf("SVAA[P]P\tnext\n");
1084 if(!iterator.next())
1085 return die_("iterator ended early\n");
1086 our_current_position++;
1088 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1089 padding->set_length(5);
1090 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1091 return die_("copying object");
1092 if(!iterator.set_block(padding, false))
1093 return die_ss_("iterator.set_block(padding, false)", iterator);
1095 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1098 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1099 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1100 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1101 return die_("copying object");
1102 if(!iterator.set_block(app, false))
1103 return die_ss_("iterator.set_block(app, false)", iterator);
1105 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1108 printf("SVAAP[A]\tset PADDING (equal)\n");
1109 padding->set_length(27);
1110 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1111 return die_("copying object");
1112 if(!iterator.set_block(padding, false))
1113 return die_ss_("iterator.set_block(padding, false)", iterator);
1115 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1118 printf("SVAAP[P]\tprev\n");
1119 if(!iterator.prev())
1120 return die_("iterator ended early\n");
1121 our_current_position--;
1123 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1124 if(!iterator.delete_block(false))
1125 return die_ss_("iterator.delete_block(false)", iterator);
1126 delete_from_our_metadata_(our_current_position--);
1128 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1131 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1132 if(!iterator.delete_block(false))
1133 return die_ss_("iterator.delete_block(false)", iterator);
1134 delete_from_our_metadata_(our_current_position--);
1136 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1139 printf("SV[A]P\tnext\n");
1140 if(!iterator.next())
1141 return die_("iterator ended early\n");
1142 our_current_position++;
1144 printf("SVA[P]\tinsert PADDING after\n");
1145 padding->set_length(5);
1146 if(!iterator.insert_block_after(padding, false))
1147 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1148 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1151 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1154 printf("SVAP[P]\tprev\n");
1155 if(!iterator.prev())
1156 return die_("iterator ended early\n");
1157 our_current_position--;
1159 printf("SVA[P]P\tprev\n");
1160 if(!iterator.prev())
1161 return die_("iterator ended early\n");
1162 our_current_position--;
1164 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1165 if(!app->set_data(data, 32, true))
1166 return die_("setting APPLICATION data");
1167 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1168 return die_("copying object");
1169 if(!iterator.set_block(app, true))
1170 return die_ss_("iterator.set_block(app, true)", iterator);
1172 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1175 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1176 if(!app->set_data(data, 60, true))
1177 return die_("setting APPLICATION data");
1178 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1179 return die_("copying object");
1180 if(!iterator.set_block(app, true))
1181 return die_ss_("iterator.set_block(app, true)", iterator);
1183 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1186 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1187 if(!app->set_data(data, 87, true))
1188 return die_("setting APPLICATION data");
1189 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1190 return die_("copying object");
1191 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1192 if(!iterator.set_block(app, true))
1193 return die_ss_("iterator.set_block(app, true)", iterator);
1195 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1198 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1199 if(!app->set_data(data, 91, true))
1200 return die_("setting APPLICATION data");
1201 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1202 return die_("copying object");
1203 delete_from_our_metadata_(our_current_position+1);
1204 if(!iterator.set_block(app, true))
1205 return die_ss_("iterator.set_block(app, true)", iterator);
1207 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1210 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1211 if(!app->set_data(data, 100, true))
1212 return die_("setting APPLICATION data");
1213 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1214 return die_("copying object");
1215 delete_from_our_metadata_(our_current_position+1);
1216 our_metadata_.blocks[our_current_position]->set_is_last(true);
1217 if(!iterator.set_block(app, true))
1218 return die_ss_("iterator.set_block(app, true)", iterator);
1220 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1223 printf("SV[A]\tset PADDING (equal size)\n");
1224 padding->set_length(app->get_length());
1225 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1226 return die_("copying object");
1227 if(!iterator.set_block(padding, true))
1228 return die_ss_("iterator.set_block(padding, true)", iterator);
1230 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1233 printf("SV[P]\tinsert PADDING after\n");
1234 if(!iterator.insert_block_after(padding, false))
1235 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1236 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1239 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1242 printf("SVP[P]\tinsert PADDING after\n");
1243 padding->set_length(5);
1244 if(!iterator.insert_block_after(padding, false))
1245 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1246 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1249 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1252 printf("SVPP[P]\tprev\n");
1253 if(!iterator.prev())
1254 return die_("iterator ended early\n");
1255 our_current_position--;
1257 printf("SVP[P]P\tprev\n");
1258 if(!iterator.prev())
1259 return die_("iterator ended early\n");
1260 our_current_position--;
1262 printf("SV[P]PP\tprev\n");
1263 if(!iterator.prev())
1264 return die_("iterator ended early\n");
1265 our_current_position--;
1267 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1268 if(!app->set_data(data, 101, true))
1269 return die_("setting APPLICATION data");
1270 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1271 return die_("copying object");
1272 if(!iterator.insert_block_after(app, true))
1273 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1275 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1278 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1279 if(!iterator.delete_block(false))
1280 return die_ss_("iterator.delete_block(false)", iterator);
1281 delete_from_our_metadata_(our_current_position--);
1283 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1286 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1287 if(!app->set_data(data, 97, true))
1288 return die_("setting APPLICATION data");
1289 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1290 return die_("copying object");
1291 if(!iterator.insert_block_after(app, true))
1292 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1294 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1297 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1298 if(!iterator.delete_block(false))
1299 return die_ss_("iterator.delete_block(false)", iterator);
1300 delete_from_our_metadata_(our_current_position--);
1302 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1305 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1306 if(!app->set_data(data, 100, true))
1307 return die_("setting APPLICATION data");
1308 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1309 return die_("copying object");
1310 delete_from_our_metadata_(our_current_position+1);
1311 if(!iterator.insert_block_after(app, true))
1312 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1314 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1317 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1318 if(!iterator.delete_block(false))
1319 return die_ss_("iterator.delete_block(false)", iterator);
1320 delete_from_our_metadata_(our_current_position--);
1322 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1325 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1326 if(!app->set_data(data, 96, true))
1327 return die_("setting APPLICATION data");
1328 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1329 return die_("copying object");
1330 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1331 if(!iterator.insert_block_after(app, true))
1332 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1334 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1337 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1338 if(!iterator.delete_block(false))
1339 return die_ss_("iterator.delete_block(false)", iterator);
1340 delete_from_our_metadata_(our_current_position--);
1342 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1345 printf("S[V]PP\tnext\n");
1346 if(!iterator.next())
1347 return die_("iterator ended early\n");
1348 our_current_position++;
1350 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1351 if(!iterator.delete_block(false))
1352 return die_ss_("iterator.delete_block(false)", iterator);
1353 delete_from_our_metadata_(our_current_position--);
1355 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1358 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1359 if(!app->set_data(data, 1, true))
1360 return die_("setting APPLICATION data");
1361 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1362 return die_("copying object");
1363 delete_from_our_metadata_(our_current_position+1);
1364 if(!iterator.insert_block_after(app, true))
1365 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1367 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1374 if(!remove_file_(flacfile_))
1380 static bool test_level_2_(bool filename_based)
1382 FLAC::Metadata::Prototype *block;
1383 FLAC::Metadata::StreamInfo *streaminfo;
1384 FLAC::Metadata::Application *app;
1385 FLAC::Metadata::Padding *padding;
1386 FLAC__byte data[2000];
1387 unsigned our_current_position;
1389 // initialize 'data' to avoid Valgrind errors
1390 memset(data, 0, sizeof(data));
1392 printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1394 printf("generate read-only file\n");
1396 if(!generate_file_(/*include_cuesheet=*/false))
1399 if(!change_stats_(flacfile_, /*read_only=*/true))
1402 printf("create chain\n");
1403 FLAC::Metadata::Chain chain;
1404 if(!chain.is_valid())
1405 return die_("allocating memory for chain");
1407 printf("read chain\n");
1409 if(!read_chain_(chain, flacfile_, filename_based))
1410 return die_c_("reading chain", chain.status());
1412 printf("[S]VP\ttest initial metadata\n");
1414 if(!compare_chain_(chain, 0, 0))
1416 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1419 printf("switch file to read-write\n");
1421 if(!change_stats_(flacfile_, /*read-only=*/false))
1424 printf("create iterator\n");
1426 FLAC::Metadata::Iterator iterator;
1427 if(!iterator.is_valid())
1428 return die_("allocating memory for iterator");
1430 our_current_position = 0;
1432 iterator.init(chain);
1434 if(0 == (block = iterator.get_block()))
1435 return die_("getting block from iterator");
1437 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1439 printf("[S]VP\tmodify STREAMINFO, write\n");
1441 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1442 FLAC__ASSERT(0 != streaminfo);
1443 streaminfo->set_sample_rate(32000);
1444 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1445 return die_("copying object");
1448 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1449 return die_c_("during chain.write(false, true)", chain.status());
1450 block = iterator.get_block();
1451 if(!compare_chain_(chain, our_current_position, block))
1454 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1457 printf("[S]VP\tnext\n");
1458 if(!iterator.next())
1459 return die_("iterator ended early\n");
1460 our_current_position++;
1462 printf("S[V]P\tnext\n");
1463 if(!iterator.next())
1464 return die_("iterator ended early\n");
1465 our_current_position++;
1467 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1468 if(0 == (block = iterator.get_block()))
1469 return die_("getting block from iterator");
1470 if(0 == (app = new FLAC::Metadata::Application()))
1471 return die_("new FLAC::Metadata::Application()");
1472 app->set_id((const unsigned char *)"duh");
1473 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1474 return die_("setting APPLICATION data");
1476 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1477 return die_("copying object");
1478 if(!iterator.set_block(app))
1479 return die_c_("iterator.set_block(app)", chain.status());
1481 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1482 return die_c_("during chain.write(false, false)", chain.status());
1483 block = iterator.get_block();
1484 if(!compare_chain_(chain, our_current_position, block))
1487 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1490 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1491 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1492 return die_("copying object");
1493 if(!app->set_data(data, 26, true))
1494 return die_("setting APPLICATION data");
1495 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1496 return die_("copying object");
1497 if(!iterator.set_block(app))
1498 return die_c_("iterator.set_block(app)", chain.status());
1500 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1501 return die_c_("during chain.write(false, false)", chain.status());
1502 block = iterator.get_block();
1503 if(!compare_chain_(chain, our_current_position, block))
1506 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1509 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1510 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1511 return die_("copying object");
1512 if(!app->set_data(data, 28, true))
1513 return die_("setting APPLICATION data");
1514 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1515 return die_("copying object");
1516 if(!iterator.set_block(app))
1517 return die_c_("iterator.set_block(app)", chain.status());
1519 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1520 return die_c_("during chain.write(false, false)", chain.status());
1521 block = iterator.get_block();
1522 if(!compare_chain_(chain, our_current_position, block))
1525 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1528 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1529 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1530 return die_("copying object");
1531 if(!app->set_data(data, 36, true))
1532 return die_("setting APPLICATION data");
1533 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1534 return die_("copying object");
1535 if(!iterator.set_block(app))
1536 return die_c_("iterator.set_block(app)", chain.status());
1538 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1539 return die_c_("during chain.write(false, false)", chain.status());
1540 block = iterator.get_block();
1541 if(!compare_chain_(chain, our_current_position, block))
1544 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1547 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1548 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1549 return die_("copying object");
1550 if(!app->set_data(data, 33, true))
1551 return die_("setting APPLICATION data");
1552 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1553 return die_("copying object");
1554 if(!iterator.set_block(app))
1555 return die_c_("iterator.set_block(app)", chain.status());
1557 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1558 return die_c_("during chain.write(true, false)", chain.status());
1559 block = iterator.get_block();
1560 if(!compare_chain_(chain, our_current_position, block))
1563 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1566 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1567 if(0 == (padding = new FLAC::Metadata::Padding()))
1568 return die_("creating PADDING block");
1569 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1570 return die_("copying object");
1571 if(!app->set_data(data, 29, true))
1572 return die_("setting APPLICATION data");
1573 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1574 return die_("copying object");
1575 padding->set_length(0);
1576 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1577 return die_("internal error");
1578 if(!iterator.set_block(app))
1579 return die_c_("iterator.set_block(app)", chain.status());
1581 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1582 return die_c_("during chain.write(true, false)", chain.status());
1583 block = iterator.get_block();
1584 if(!compare_chain_(chain, our_current_position, block))
1587 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1590 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1591 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1592 return die_("copying object");
1593 if(!app->set_data(data, 16, true))
1594 return die_("setting APPLICATION data");
1595 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1596 return die_("copying object");
1597 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1598 if(!iterator.set_block(app))
1599 return die_c_("iterator.set_block(app)", chain.status());
1601 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1602 return die_c_("during chain.write(true, false)", chain.status());
1603 block = iterator.get_block();
1604 if(!compare_chain_(chain, our_current_position, block))
1607 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1610 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1611 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1612 return die_("copying object");
1613 if(!app->set_data(data, 50, true))
1614 return die_("setting APPLICATION data");
1615 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1616 return die_("copying object");
1617 if(!iterator.set_block(app))
1618 return die_c_("iterator.set_block(app)", chain.status());
1620 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1621 return die_c_("during chain.write(true, false)", chain.status());
1622 block = iterator.get_block();
1623 if(!compare_chain_(chain, our_current_position, block))
1626 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1629 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1630 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1631 return die_("copying object");
1632 if(!app->set_data(data, 56, true))
1633 return die_("setting APPLICATION data");
1634 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1635 return die_("copying object");
1636 add_to_padding_length_(our_current_position+1, -(56 - 50));
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, flacfile_))
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_(flacfile_, /*ignore_metadata=*/false))
1649 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1650 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1651 return die_("copying object");
1652 if(!app->set_data(data, 67, true))
1653 return die_("setting APPLICATION data");
1654 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1655 return die_("copying object");
1656 delete_from_our_metadata_(our_current_position+1);
1657 if(!iterator.set_block(app))
1658 return die_c_("iterator.set_block(app)", chain.status());
1660 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1661 return die_c_("during chain.write(true, false)", chain.status());
1662 block = iterator.get_block();
1663 if(!compare_chain_(chain, our_current_position, block))
1666 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1669 printf("SV[A]\tprev\n");
1670 if(!iterator.prev())
1671 return die_("iterator ended early\n");
1672 our_current_position--;
1674 printf("S[V]A\tprev\n");
1675 if(!iterator.prev())
1676 return die_("iterator ended early\n");
1677 our_current_position--;
1679 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1680 if(0 == (padding = new FLAC::Metadata::Padding()))
1681 return die_("creating PADDING block");
1682 padding->set_length(30);
1683 if(!iterator.insert_block_before(padding))
1684 printf("\titerator.insert_block_before() returned false like it should\n");
1686 return die_("iterator.insert_block_before() should have returned false");
1688 printf("[S]VA\tnext\n");
1689 if(!iterator.next())
1690 return die_("iterator ended early\n");
1691 our_current_position++;
1693 printf("S[V]A\tinsert PADDING after\n");
1694 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1695 return die_("copying metadata");
1696 if(!iterator.insert_block_after(padding))
1697 return die_("iterator.insert_block_after(padding)");
1699 block = iterator.get_block();
1700 if(!compare_chain_(chain, our_current_position, block))
1704 printf("SV[P]A\tinsert PADDING before\n");
1705 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1706 return die_("creating PADDING block");
1707 padding->set_length(17);
1708 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1709 return die_("copying metadata");
1710 if(!iterator.insert_block_before(padding))
1711 return die_("iterator.insert_block_before(padding)");
1713 block = iterator.get_block();
1714 if(!compare_chain_(chain, our_current_position, block))
1718 printf("SV[P]PA\tinsert PADDING before\n");
1719 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1720 return die_("creating PADDING block");
1721 padding->set_length(0);
1722 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1723 return die_("copying metadata");
1724 if(!iterator.insert_block_before(padding))
1725 return die_("iterator.insert_block_before(padding)");
1727 block = iterator.get_block();
1728 if(!compare_chain_(chain, our_current_position, block))
1732 printf("SV[P]PPA\tnext\n");
1733 if(!iterator.next())
1734 return die_("iterator ended early\n");
1735 our_current_position++;
1737 printf("SVP[P]PA\tnext\n");
1738 if(!iterator.next())
1739 return die_("iterator ended early\n");
1740 our_current_position++;
1742 printf("SVPP[P]A\tnext\n");
1743 if(!iterator.next())
1744 return die_("iterator ended early\n");
1745 our_current_position++;
1747 printf("SVPPP[A]\tinsert PADDING after\n");
1748 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1749 return die_("creating PADDING block");
1750 padding->set_length(57);
1751 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1752 return die_("copying metadata");
1753 if(!iterator.insert_block_after(padding))
1754 return die_("iterator.insert_block_after(padding)");
1756 block = iterator.get_block();
1757 if(!compare_chain_(chain, our_current_position, block))
1761 printf("SVPPPA[P]\tinsert PADDING before\n");
1762 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1763 return die_("creating PADDING block");
1764 padding->set_length(99);
1765 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1766 return die_("copying metadata");
1767 if(!iterator.insert_block_before(padding))
1768 return die_("iterator.insert_block_before(padding)");
1770 block = iterator.get_block();
1771 if(!compare_chain_(chain, our_current_position, block))
1776 our_current_position = 0;
1778 printf("SVPPPAPP\tmerge padding\n");
1779 chain.merge_padding();
1780 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1781 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1782 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1783 delete_from_our_metadata_(7);
1784 delete_from_our_metadata_(4);
1785 delete_from_our_metadata_(3);
1787 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1788 return die_c_("during chain.write(true, false)", chain.status());
1789 if(!compare_chain_(chain, 0, 0))
1791 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1794 printf("SVPAP\tsort padding\n");
1795 chain.sort_padding();
1796 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1797 delete_from_our_metadata_(2);
1799 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1800 return die_c_("during chain.write(true, false)", chain.status());
1801 if(!compare_chain_(chain, 0, 0))
1803 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1806 printf("create iterator\n");
1808 FLAC::Metadata::Iterator iterator;
1809 if(!iterator.is_valid())
1810 return die_("allocating memory for iterator");
1812 our_current_position = 0;
1814 iterator.init(chain);
1816 printf("[S]VAP\tnext\n");
1817 if(!iterator.next())
1818 return die_("iterator ended early\n");
1819 our_current_position++;
1821 printf("S[V]AP\tnext\n");
1822 if(!iterator.next())
1823 return die_("iterator ended early\n");
1824 our_current_position++;
1826 printf("SV[A]P\tdelete middle block, replace with padding\n");
1827 if(0 == (padding = new FLAC::Metadata::Padding()))
1828 return die_("creating PADDING block");
1829 padding->set_length(71);
1830 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1831 return die_("copying object");
1832 if(!iterator.delete_block(/*replace_with_padding=*/true))
1833 return die_c_("iterator.delete_block(true)", chain.status());
1835 block = iterator.get_block();
1836 if(!compare_chain_(chain, our_current_position, block))
1840 printf("S[V]PP\tnext\n");
1841 if(!iterator.next())
1842 return die_("iterator ended early\n");
1843 our_current_position++;
1845 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1846 delete_from_our_metadata_(our_current_position--);
1847 if(!iterator.delete_block(/*replace_with_padding=*/false))
1848 return die_c_("iterator.delete_block(false)", chain.status());
1850 block = iterator.get_block();
1851 if(!compare_chain_(chain, our_current_position, block))
1855 printf("S[V]P\tnext\n");
1856 if(!iterator.next())
1857 return die_("iterator ended early\n");
1858 our_current_position++;
1860 printf("SV[P]\tdelete last block, replace with padding\n");
1861 if(0 == (padding = new FLAC::Metadata::Padding()))
1862 return die_("creating PADDING block");
1863 padding->set_length(219);
1864 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1865 return die_("copying object");
1866 if(!iterator.delete_block(/*replace_with_padding=*/true))
1867 return die_c_("iterator.delete_block(true)", chain.status());
1869 block = iterator.get_block();
1870 if(!compare_chain_(chain, our_current_position, block))
1874 printf("S[V]P\tnext\n");
1875 if(!iterator.next())
1876 return die_("iterator ended early\n");
1877 our_current_position++;
1879 printf("SV[P]\tdelete last block, don't replace with padding\n");
1880 delete_from_our_metadata_(our_current_position--);
1881 if(!iterator.delete_block(/*replace_with_padding=*/false))
1882 return die_c_("iterator.delete_block(false)", chain.status());
1884 block = iterator.get_block();
1885 if(!compare_chain_(chain, our_current_position, block))
1889 printf("S[V]\tprev\n");
1890 if(!iterator.prev())
1891 return die_("iterator ended early\n");
1892 our_current_position--;
1894 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1895 if(iterator.delete_block(/*replace_with_padding=*/false))
1896 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1898 block = iterator.get_block();
1899 if(!compare_chain_(chain, our_current_position, block))
1903 } // delete iterator
1904 our_current_position = 0;
1906 printf("SV\tmerge padding\n");
1907 chain.merge_padding();
1909 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1910 return die_c_("during chain.write(false, false)", chain.status());
1911 if(!compare_chain_(chain, 0, 0))
1913 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1916 printf("SV\tsort padding\n");
1917 chain.sort_padding();
1919 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1920 return die_c_("during chain.write(false, false)", chain.status());
1921 if(!compare_chain_(chain, 0, 0))
1923 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1926 if(!remove_file_(flacfile_))
1932 static bool test_level_2_misc_()
1934 ::FLAC__IOCallbacks callbacks;
1936 memset(&callbacks, 0, sizeof(callbacks));
1937 callbacks.read = (::FLAC__IOCallback_Read)fread;
1938 #ifdef FLAC__VALGRIND_TESTING
1939 callbacks.write = chain_write_cb_;
1941 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
1943 callbacks.seek = chain_seek_cb_;
1944 callbacks.tell = chain_tell_cb_;
1945 callbacks.eof = chain_eof_cb_;
1947 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1949 printf("generate file\n");
1951 if(!generate_file_(/*include_cuesheet=*/false))
1954 printf("create chain\n");
1955 FLAC::Metadata::Chain chain;
1956 if(!chain.is_valid())
1957 return die_("allocating chain");
1959 printf("read chain (filename-based)\n");
1961 if(!chain.read(flacfile_))
1962 return die_c_("reading chain", chain.status());
1964 printf("write chain with wrong method Chain::write(with callbacks)\n");
1966 if(chain.write(/*use_padding=*/false, 0, callbacks))
1967 return die_c_("mismatched write should have failed", chain.status());
1968 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1969 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
1970 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1973 printf("read chain (filename-based)\n");
1975 if(!chain.read(flacfile_))
1976 return die_c_("reading chain", chain.status());
1978 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
1980 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
1981 return die_c_("mismatched write should have failed", chain.status());
1982 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1983 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
1984 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1987 printf("read chain (callback-based)\n");
1989 FILE *file = fopen(flacfile_, "rb");
1991 return die_("opening file");
1992 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
1994 return die_c_("reading chain", chain.status());
1999 printf("write chain with wrong method write()\n");
2001 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2002 return die_c_("mismatched write should have failed", chain.status());
2003 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2004 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2005 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2008 printf("read chain (callback-based)\n");
2010 FILE *file = fopen(flacfile_, "rb");
2012 return die_("opening file");
2013 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2015 return die_c_("reading chain", chain.status());
2020 printf("testing Chain::check_if_tempfile_needed()... ");
2022 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2023 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2025 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2027 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2029 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2030 return die_c_("mismatched write should have failed", chain.status());
2031 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2032 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2033 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2036 printf("read chain (callback-based)\n");
2038 FILE *file = fopen(flacfile_, "rb");
2040 return die_("opening file");
2041 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2043 return die_c_("reading chain", chain.status());
2048 printf("create iterator\n");
2050 FLAC::Metadata::Iterator iterator;
2051 if(!iterator.is_valid())
2052 return die_("allocating memory for iterator");
2054 iterator.init(chain);
2056 printf("[S]VP\tnext\n");
2057 if(!iterator.next())
2058 return die_("iterator ended early\n");
2060 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2061 if(!iterator.delete_block(/*replace_with_padding=*/false))
2062 return die_c_("block delete failed\n", chain.status());
2064 printf("testing Chain::check_if_tempfile_needed()... ");
2066 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2067 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2069 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2071 printf("write chain with wrong method Chain::write(with callbacks)\n");
2073 if(chain.write(/*use_padding=*/false, 0, callbacks))
2074 return die_c_("mismatched write should have failed", chain.status());
2075 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2076 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2077 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2080 } // delete iterator
2082 if(!remove_file_(flacfile_))
2088 bool test_metadata_file_manipulation()
2090 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2092 our_metadata_.num_blocks = 0;
2094 if(!test_level_0_())
2097 if(!test_level_1_())
2100 if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2102 if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2104 if(!test_level_2_misc_())