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 "file_utils.h"
22 #include "FLAC/assert.h"
23 #include "FLAC++/decoder.h"
24 #include "FLAC++/metadata.h"
25 #include "share/grabbag.h"
27 #include <stdlib.h> /* for malloc() */
28 #include <string.h> /* for memcpy()/memset() */
30 #if defined _MSC_VER || defined __MINGW32__
31 #include <sys/utime.h> /* for utime() */
32 #include <io.h> /* for chmod() */
34 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
35 #include <utime.h> /* for utime() */
36 #include <unistd.h> /* for chown(), unlink() */
38 #include <sys/stat.h> /* for stat(), maybe chmod() */
40 /******************************************************************************
41 The general strategy of these tests (for interface levels 1 and 2) is
42 to create a dummy FLAC file with a known set of initial metadata
43 blocks, then keep a mirror locally of what we expect the metadata to be
44 after each operation. Then testing becomes a simple matter of running
45 a FLAC::Decoder::File over the dummy file after each operation, comparing
46 the decoded metadata to what's in our local copy. If there are any
47 differences in the metadata, or the actual audio data is corrupted, we
48 will catch it while decoding.
49 ******************************************************************************/
51 class OurFileDecoder: public FLAC::Decoder::File {
53 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
55 bool ignore_metadata_;
58 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
59 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
60 void error_callback(::FLAC__StreamDecoderErrorStatus status);
64 FLAC::Metadata::Prototype *blocks[64];
68 static const char *flacfile_ = "metadata.flac";
70 /* our copy of the metadata in flacfile_ */
71 static OurMetadata our_metadata_;
73 /* the current block number that corresponds to the position of the iterator we are testing */
74 static unsigned mc_our_block_number_ = 0;
76 static bool die_(const char *msg)
78 printf("ERROR: %s\n", msg);
82 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
84 printf("ERROR: %s\n", msg);
85 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
89 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
91 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
92 printf("ERROR: %s\n", msg);
93 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
97 static void *malloc_or_die_(size_t size)
99 void *x = malloc(size);
101 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
107 /* functions for working with our metadata copy */
109 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
112 FLAC::Metadata::Prototype *obj = block;
113 FLAC__ASSERT(position < our_metadata_.num_blocks);
115 if(0 == (obj = FLAC::Metadata::clone(block)))
116 return die_("during FLAC::Metadata::clone()");
118 delete our_metadata_.blocks[position];
119 our_metadata_.blocks[position] = obj;
121 /* set the is_last flags */
122 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
123 our_metadata_.blocks[i]->set_is_last(false);
124 our_metadata_.blocks[i]->set_is_last(true);
129 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
132 FLAC::Metadata::Prototype *obj = block;
134 if(0 == (obj = FLAC::Metadata::clone(block)))
135 return die_("during FLAC::Metadata::clone()");
137 if(position > our_metadata_.num_blocks) {
138 position = our_metadata_.num_blocks;
141 for(i = our_metadata_.num_blocks; i > position; i--)
142 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
144 our_metadata_.blocks[position] = obj;
145 our_metadata_.num_blocks++;
147 /* set the is_last flags */
148 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
149 our_metadata_.blocks[i]->set_is_last(false);
150 our_metadata_.blocks[i]->set_is_last(true);
155 static void delete_from_our_metadata_(unsigned position)
158 FLAC__ASSERT(position < our_metadata_.num_blocks);
159 delete our_metadata_.blocks[position];
160 for(i = position; i < our_metadata_.num_blocks - 1; i++)
161 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
162 our_metadata_.num_blocks--;
164 /* set the is_last flags */
165 if(our_metadata_.num_blocks > 0) {
166 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
167 our_metadata_.blocks[i]->set_is_last(false);
168 our_metadata_.blocks[i]->set_is_last(true);
172 void add_to_padding_length_(unsigned index, int delta)
174 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
175 FLAC__ASSERT(0 != padding);
176 padding->set_length((unsigned)((int)padding->get_length() + delta));
180 * This wad of functions supports filename- and callback-based chain reading/writing.
181 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
183 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
185 static const char *tempfile_suffix = ".metadata_edit";
187 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
189 strcpy(*tempfilename, filename);
190 strcat(*tempfilename, tempfile_suffix);
192 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
198 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
201 (void)fclose(*tempfile);
205 if(0 != *tempfilename) {
206 (void)unlink(*tempfilename);
212 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
214 FLAC__ASSERT(0 != filename);
215 FLAC__ASSERT(0 != tempfile);
216 FLAC__ASSERT(0 != tempfilename);
217 FLAC__ASSERT(0 != *tempfilename);
220 (void)fclose(*tempfile);
224 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
225 if(unlink(filename) < 0) {
226 cleanup_tempfile_(tempfile, tempfilename);
231 if(0 != rename(*tempfilename, filename)) {
232 cleanup_tempfile_(tempfile, tempfilename);
236 cleanup_tempfile_(tempfile, tempfilename);
241 bool get_file_stats_(const char *filename, struct stat *stats)
243 FLAC__ASSERT(0 != filename);
244 FLAC__ASSERT(0 != stats);
245 return (0 == stat(filename, stats));
248 void set_file_stats_(const char *filename, struct stat *stats)
250 struct utimbuf srctime;
252 FLAC__ASSERT(0 != filename);
253 FLAC__ASSERT(0 != stats);
255 srctime.actime = stats->st_atime;
256 srctime.modtime = stats->st_mtime;
257 (void)chmod(filename, stats->st_mode);
258 (void)utime(filename, &srctime);
259 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
260 (void)chown(filename, stats->st_uid, (gid_t)(-1));
261 (void)chown(filename, (uid_t)(-1), stats->st_gid);
265 #ifdef FLAC__VALGRIND_TESTING
266 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
268 FILE *stream = (FILE*)handle;
269 size_t ret = fwrite(ptr, size, nmemb, stream);
276 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
278 long o = (long)offset;
279 FLAC__ASSERT(offset == o);
280 return fseek((FILE*)handle, o, whence);
283 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
285 return ftell((FILE*)handle);
288 static int chain_eof_cb_(::FLAC__IOHandle handle)
290 return feof((FILE*)handle);
293 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
296 return chain.write(use_padding, preserve_file_stats);
298 ::FLAC__IOCallbacks callbacks;
300 memset(&callbacks, 0, sizeof(callbacks));
301 callbacks.read = (::FLAC__IOCallback_Read)fread;
302 #ifdef FLAC__VALGRIND_TESTING
303 callbacks.write = chain_write_cb_;
305 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
307 callbacks.seek = chain_seek_cb_;
308 callbacks.eof = chain_eof_cb_;
310 if(chain.check_if_tempfile_needed(use_padding)) {
312 FILE *file, *tempfile;
314 if(preserve_file_stats) {
315 if(!get_file_stats_(filename, &stats))
318 if(0 == (file = fopen(filename, "rb")))
319 return false; /*@@@ chain status still says OK though */
320 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
322 cleanup_tempfile_(&tempfile, &tempfilename);
323 return false; /*@@@ chain status still says OK though */
325 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
333 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
335 if(preserve_file_stats)
336 set_file_stats_(filename, &stats);
339 FILE *file = fopen(filename, "r+b");
341 return false; /*@@@ chain status still says OK though */
342 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
351 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
354 return chain.read(filename);
356 ::FLAC__IOCallbacks callbacks;
358 memset(&callbacks, 0, sizeof(callbacks));
359 callbacks.read = (::FLAC__IOCallback_Read)fread;
360 callbacks.seek = chain_seek_cb_;
361 callbacks.tell = chain_tell_cb_;
365 FILE *file = fopen(filename, "rb");
367 return false; /*@@@ chain status still says OK though */
368 ret = chain.read((::FLAC__IOHandle)file, callbacks);
375 /* function for comparing our metadata to a FLAC::Metadata::Chain */
377 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
380 FLAC::Metadata::Iterator iterator;
383 printf("\tcomparing chain... ");
386 if(!iterator.is_valid())
387 return die_("allocating memory for iterator");
389 iterator.init(chain);
393 FLAC::Metadata::Prototype *block;
398 if(0 == (block = iterator.get_block()))
399 return die_("getting block from iterator");
401 if(*block != *our_metadata_.blocks[i])
402 return die_("metadata block mismatch");
406 next_ok = iterator.next();
407 } while(i < our_metadata_.num_blocks && next_ok);
410 return die_("chain has more blocks than expected");
412 if(i < our_metadata_.num_blocks)
413 return die_("short block count in chain");
415 if(0 != current_block) {
416 printf("CURRENT_POSITION... ");
419 if(*current_block != *our_metadata_.blocks[current_position])
420 return die_("metadata block mismatch");
428 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
433 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
434 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
436 printf("content... ");
440 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
443 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
445 /* don't bother checking if we've already hit an error */
449 printf("%d... ", mc_our_block_number_);
452 if(!ignore_metadata_) {
453 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
454 (void)die_("got more metadata blocks than expected");
455 error_occurred_ = true;
458 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
459 (void)die_("metadata block mismatch");
460 error_occurred_ = true;
465 mc_our_block_number_++;
468 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
470 error_occurred_ = true;
471 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
474 static bool generate_file_(FLAC__bool include_cuesheet)
476 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
477 ::FLAC__StreamMetadata *metadata[3];
478 unsigned i = 0, n = 0;
480 printf("generating FLAC file for test\n");
482 while(our_metadata_.num_blocks > 0)
483 delete_from_our_metadata_(0);
485 streaminfo.is_last = false;
486 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
487 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
488 streaminfo.data.stream_info.min_blocksize = 576;
489 streaminfo.data.stream_info.max_blocksize = 576;
490 streaminfo.data.stream_info.min_framesize = 0;
491 streaminfo.data.stream_info.max_framesize = 0;
492 streaminfo.data.stream_info.sample_rate = 44100;
493 streaminfo.data.stream_info.channels = 1;
494 streaminfo.data.stream_info.bits_per_sample = 8;
495 streaminfo.data.stream_info.total_samples = 0;
496 memset(streaminfo.data.stream_info.md5sum, 0, 16);
499 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
500 vorbiscomment.is_last = false;
501 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
502 vorbiscomment.length = (4 + vendor_string_length) + 4;
503 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
504 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
505 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
506 vorbiscomment.data.vorbis_comment.num_comments = 0;
507 vorbiscomment.data.vorbis_comment.comments = 0;
511 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
512 return die_("priming our metadata");
513 cuesheet->is_last = false;
514 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
515 cuesheet->data.cue_sheet.lead_in = 123;
516 cuesheet->data.cue_sheet.is_cd = false;
517 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
518 return die_("priming our metadata");
519 cuesheet->data.cue_sheet.tracks[0].number = 1;
520 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
521 return die_("priming our metadata");
524 padding.is_last = true;
525 padding.type = ::FLAC__METADATA_TYPE_PADDING;
526 padding.length = 1234;
528 metadata[n++] = &vorbiscomment;
529 if (include_cuesheet)
530 metadata[n++] = cuesheet;
531 metadata[n++] = &padding;
533 FLAC::Metadata::StreamInfo s(&streaminfo);
534 FLAC::Metadata::VorbisComment v(&vorbiscomment);
535 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
536 FLAC::Metadata::Padding p(&padding);
538 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
539 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
540 (include_cuesheet && !insert_to_our_metadata_(&v, i++, /*copy=*/true)) ||
541 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
543 return die_("priming our metadata");
545 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
546 return die_("creating the encoded file");
548 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
553 static bool test_file_(const char *filename, bool ignore_metadata)
555 OurFileDecoder decoder(ignore_metadata);
557 FLAC__ASSERT(0 != filename);
559 mc_our_block_number_ = 0;
560 decoder.error_occurred_ = false;
562 printf("\ttesting '%s'... ", filename);
565 if(!decoder.is_valid())
566 return die_("couldn't allocate decoder instance");
568 decoder.set_md5_checking(true);
569 decoder.set_filename(filename);
570 decoder.set_metadata_respond_all();
571 if(decoder.init() != ::FLAC__FILE_DECODER_OK) {
573 return die_("initializing decoder\n");
575 if(!decoder.process_until_end_of_file()) {
577 return die_("decoding file\n");
582 if(decoder.error_occurred_)
585 if(mc_our_block_number_ != our_metadata_.num_blocks)
586 return die_("short metadata block count");
592 static bool change_stats_(const char *filename, bool read_only)
594 if(!grabbag__file_change_stats(filename, read_only))
595 return die_("during grabbag__file_change_stats()");
600 static bool remove_file_(const char *filename)
602 while(our_metadata_.num_blocks > 0)
603 delete_from_our_metadata_(0);
605 if(!grabbag__file_remove_file(filename))
606 return die_("removing file");
611 static bool test_level_0_()
613 FLAC::Metadata::StreamInfo streaminfo;
615 printf("\n\n++++++ testing level 0 interface\n");
617 if(!generate_file_(/*include_cuesheet=*/true))
620 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
623 printf("testing FLAC::Metadata::get_streaminfo()... ");
625 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
626 return die_("during FLAC::Metadata::get_streaminfo()");
628 /* check to see if some basic data matches (c.f. generate_file_()) */
629 if(streaminfo.get_channels() != 1)
630 return die_("mismatch in streaminfo.get_channels()");
631 if(streaminfo.get_bits_per_sample() != 8)
632 return die_("mismatch in streaminfo.get_bits_per_sample()");
633 if(streaminfo.get_sample_rate() != 44100)
634 return die_("mismatch in streaminfo.get_sample_rate()");
635 if(streaminfo.get_min_blocksize() != 576)
636 return die_("mismatch in streaminfo.get_min_blocksize()");
637 if(streaminfo.get_max_blocksize() != 576)
638 return die_("mismatch in streaminfo.get_max_blocksize()");
643 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
645 FLAC::Metadata::VorbisComment *tags = 0;
647 if(!FLAC::Metadata::get_tags(flacfile_, tags))
648 return die_("during FLAC::Metadata::get_tags()");
650 /* check to see if some basic data matches (c.f. generate_file_()) */
651 if(tags->get_num_comments() != 0)
652 return die_("mismatch in tags->get_num_comments()");
660 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
662 FLAC::Metadata::VorbisComment tags;
664 if(!FLAC::Metadata::get_tags(flacfile_, tags))
665 return die_("during FLAC::Metadata::get_tags()");
667 /* check to see if some basic data matches (c.f. generate_file_()) */
668 if(tags.get_num_comments() != 0)
669 return die_("mismatch in tags.get_num_comments()");
675 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
677 FLAC::Metadata::CueSheet *cuesheet = 0;
679 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
680 return die_("during FLAC::Metadata::get_cuesheet()");
682 /* check to see if some basic data matches (c.f. generate_file_()) */
683 if(cuesheet->get_lead_in() != 123)
684 return die_("mismatch in cuesheet->get_lead_in()");
692 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
694 FLAC::Metadata::CueSheet cuesheet;
696 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
697 return die_("during FLAC::Metadata::get_cuesheet()");
699 /* check to see if some basic data matches (c.f. generate_file_()) */
700 if(cuesheet.get_lead_in() != 123)
701 return die_("mismatch in cuesheet.get_lead_in()");
706 if(!remove_file_(flacfile_))
712 static bool test_level_1_()
714 FLAC::Metadata::Prototype *block;
715 FLAC::Metadata::StreamInfo *streaminfo;
716 FLAC::Metadata::Padding *padding;
717 FLAC::Metadata::Application *app;
718 FLAC__byte data[1000];
719 unsigned our_current_position = 0;
721 // initialize 'data' to avoid Valgrind errors
722 memset(data, 0, sizeof(data));
724 printf("\n\n++++++ testing level 1 interface\n");
726 /************************************************************/
728 printf("simple iterator on read-only file\n");
730 if(!generate_file_(/*include_cuesheet=*/false))
733 if(!change_stats_(flacfile_, /*read_only=*/true))
736 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
739 FLAC::Metadata::SimpleIterator iterator;
741 if(!iterator.is_valid())
742 return die_("iterator.is_valid() returned false");
744 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
745 return die_("iterator.init() returned false");
747 printf("is writable = %u\n", (unsigned)iterator.is_writable());
748 if(iterator.is_writable())
749 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
751 printf("iterate forwards\n");
753 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
754 return die_("expected STREAMINFO type from iterator.get_block_type()");
755 if(0 == (block = iterator.get_block()))
756 return die_("getting block 0");
757 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
758 return die_("expected STREAMINFO type");
759 if(block->get_is_last())
760 return die_("expected is_last to be false");
761 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
762 return die_("bad STREAMINFO length");
763 /* check to see if some basic data matches (c.f. generate_file_()) */
764 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
765 FLAC__ASSERT(0 != streaminfo);
766 if(streaminfo->get_channels() != 1)
767 return die_("mismatch in channels");
768 if(streaminfo->get_bits_per_sample() != 8)
769 return die_("mismatch in bits_per_sample");
770 if(streaminfo->get_sample_rate() != 44100)
771 return die_("mismatch in sample_rate");
772 if(streaminfo->get_min_blocksize() != 576)
773 return die_("mismatch in min_blocksize");
774 if(streaminfo->get_max_blocksize() != 576)
775 return die_("mismatch in max_blocksize");
776 // we will delete streaminfo a little later when we're really done with it...
779 return die_("forward iterator ended early");
780 our_current_position++;
783 return die_("forward iterator ended early");
784 our_current_position++;
786 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
787 return die_("expected PADDING type from iterator.get_block_type()");
788 if(0 == (block = iterator.get_block()))
789 return die_("getting block 1");
790 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
791 return die_("expected PADDING type");
792 if(!block->get_is_last())
793 return die_("expected is_last to be true");
794 /* check to see if some basic data matches (c.f. generate_file_()) */
795 if(block->get_length() != 1234)
796 return die_("bad PADDING length");
800 return die_("forward iterator returned true but should have returned false");
802 printf("iterate backwards\n");
804 return die_("reverse iterator ended early");
806 return die_("reverse iterator ended early");
808 return die_("reverse iterator returned true but should have returned false");
810 printf("testing iterator.set_block() on read-only file...\n");
812 if(!iterator.set_block(streaminfo, false))
813 printf("PASSED. iterator.set_block() returned false like it should\n");
815 return die_("iterator.set_block() returned true but shouldn't have");
819 /************************************************************/
821 printf("simple iterator on writable file\n");
823 if(!change_stats_(flacfile_, /*read-only=*/false))
826 printf("creating APPLICATION block\n");
828 if(0 == (app = new FLAC::Metadata::Application()))
829 return die_("new FLAC::Metadata::Application()");
830 app->set_id((const unsigned char *)"duh");
832 printf("creating PADDING block\n");
834 if(0 == (padding = new FLAC::Metadata::Padding()))
835 return die_("new FLAC::Metadata::Padding()");
836 padding->set_length(20);
838 FLAC::Metadata::SimpleIterator iterator;
840 if(!iterator.is_valid())
841 return die_("iterator.is_valid() returned false");
843 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
844 return die_("iterator.init() returned false");
845 our_current_position = 0;
847 printf("is writable = %u\n", (unsigned)iterator.is_writable());
849 printf("[S]VP\ttry to write over STREAMINFO block...\n");
850 if(!iterator.set_block(app, false))
851 printf("\titerator.set_block() returned false like it should\n");
853 return die_("iterator.set_block() returned true but shouldn't have");
855 printf("[S]VP\tnext\n");
857 return die_("iterator ended early\n");
858 our_current_position++;
860 printf("S[V]P\tnext\n");
862 return die_("iterator ended early\n");
863 our_current_position++;
865 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
866 padding->set_length(25);
867 if(!iterator.insert_block_after(padding, false))
868 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
869 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
872 printf("SVP[P]\tprev\n");
874 return die_("iterator ended early\n");
875 our_current_position--;
877 printf("SV[P]P\tprev\n");
879 return die_("iterator ended early\n");
880 our_current_position--;
882 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
883 padding->set_length(30);
884 if(!iterator.insert_block_after(padding, false))
885 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
886 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
889 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
892 printf("SV[P]PP\tprev\n");
894 return die_("iterator ended early\n");
895 our_current_position--;
897 printf("S[V]PPP\tprev\n");
899 return die_("iterator ended early\n");
900 our_current_position--;
902 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
903 if(iterator.delete_block(false))
904 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
906 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
909 printf("[S]VPPP\tnext\n");
911 return die_("iterator ended early\n");
912 our_current_position++;
914 printf("S[V]PPP\tnext\n");
916 return die_("iterator ended early\n");
917 our_current_position++;
919 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
920 if(!iterator.delete_block(true))
921 return die_ss_("iterator.delete_block(true)", iterator);
922 our_current_position--;
924 printf("S[V]PPP\tnext\n");
926 return die_("iterator ended early\n");
927 our_current_position++;
929 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
930 if(!iterator.delete_block(false))
931 return die_ss_("iterator.delete_block(false)", iterator);
932 delete_from_our_metadata_(our_current_position--);
934 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
937 printf("S[V]PP\tnext\n");
939 return die_("iterator ended early\n");
940 our_current_position++;
942 printf("SV[P]P\tnext\n");
944 return die_("iterator ended early\n");
945 our_current_position++;
947 printf("SVP[P]\tdelete (last block), replace with padding\n");
948 if(!iterator.delete_block(true))
949 return die_ss_("iterator.delete_block(false)", iterator);
950 our_current_position--;
952 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
955 printf("SV[P]P\tnext\n");
957 return die_("iterator ended early\n");
958 our_current_position++;
960 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
961 if(!iterator.delete_block(false))
962 return die_ss_("iterator.delete_block(false)", iterator);
963 delete_from_our_metadata_(our_current_position--);
965 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
968 printf("SV[P]\tprev\n");
970 return die_("iterator ended early\n");
971 our_current_position--;
973 printf("S[V]P\tprev\n");
975 return die_("iterator ended early\n");
976 our_current_position--;
978 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
979 FLAC__ASSERT(our_current_position == 0);
980 block = iterator.get_block();
981 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
982 FLAC__ASSERT(0 != streaminfo);
983 streaminfo->set_sample_rate(32000);
984 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
985 return die_("copying object");
986 if(!iterator.set_block(block, false))
987 return die_ss_("iterator.set_block(block, false)", iterator);
990 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
993 printf("[S]VP\tnext\n");
995 return die_("iterator ended early\n");
996 our_current_position++;
998 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
999 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1000 if(!iterator.insert_block_after(app, true))
1001 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1002 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1004 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1006 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1009 printf("SV[A]P\tnext\n");
1010 if(!iterator.next())
1011 return die_("iterator ended early\n");
1012 our_current_position++;
1014 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1015 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1016 if(!iterator.set_block(app, true))
1017 return die_ss_("iterator.set_block(app, true)", iterator);
1018 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1020 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1022 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1025 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1026 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1027 if(!app->set_data(data, sizeof(data), true))
1028 return die_("setting APPLICATION data");
1029 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1030 return die_("copying object");
1031 if(!iterator.set_block(app, false))
1032 return die_ss_("iterator.set_block(app, false)", iterator);
1034 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1037 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1038 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1039 if(!app->set_data(data, 12, true))
1040 return die_("setting APPLICATION data");
1041 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1042 return die_("copying object");
1043 if(!iterator.set_block(app, false))
1044 return die_ss_("iterator.set_block(app, false)", iterator);
1046 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1049 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1050 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1051 if(!app->set_data(data, sizeof(data), true))
1052 return die_("setting APPLICATION data");
1053 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1054 return die_("copying object");
1055 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1056 if(!iterator.set_block(app, true))
1057 return die_ss_("iterator.set_block(app, true)", iterator);
1059 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1062 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1063 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1064 if(!app->set_data(data, 23, true))
1065 return die_("setting APPLICATION data");
1066 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1067 return die_("copying object");
1068 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1069 return die_("copying object");
1070 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1071 if(!iterator.set_block(app, true))
1072 return die_ss_("iterator.set_block(app, true)", iterator);
1074 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1077 printf("SVA[A]PP\tnext\n");
1078 if(!iterator.next())
1079 return die_("iterator ended early\n");
1080 our_current_position++;
1082 printf("SVAA[P]P\tnext\n");
1083 if(!iterator.next())
1084 return die_("iterator ended early\n");
1085 our_current_position++;
1087 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1088 padding->set_length(5);
1089 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1090 return die_("copying object");
1091 if(!iterator.set_block(padding, false))
1092 return die_ss_("iterator.set_block(padding, false)", iterator);
1094 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1097 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1098 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1099 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1100 return die_("copying object");
1101 if(!iterator.set_block(app, false))
1102 return die_ss_("iterator.set_block(app, false)", iterator);
1104 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1107 printf("SVAAP[A]\tset PADDING (equal)\n");
1108 padding->set_length(27);
1109 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1110 return die_("copying object");
1111 if(!iterator.set_block(padding, false))
1112 return die_ss_("iterator.set_block(padding, false)", iterator);
1114 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1117 printf("SVAAP[P]\tprev\n");
1118 if(!iterator.prev())
1119 return die_("iterator ended early\n");
1120 our_current_position--;
1122 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1123 if(!iterator.delete_block(false))
1124 return die_ss_("iterator.delete_block(false)", iterator);
1125 delete_from_our_metadata_(our_current_position--);
1127 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1130 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1131 if(!iterator.delete_block(false))
1132 return die_ss_("iterator.delete_block(false)", iterator);
1133 delete_from_our_metadata_(our_current_position--);
1135 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1138 printf("SV[A]P\tnext\n");
1139 if(!iterator.next())
1140 return die_("iterator ended early\n");
1141 our_current_position++;
1143 printf("SVA[P]\tinsert PADDING after\n");
1144 padding->set_length(5);
1145 if(!iterator.insert_block_after(padding, false))
1146 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1147 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1150 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1153 printf("SVAP[P]\tprev\n");
1154 if(!iterator.prev())
1155 return die_("iterator ended early\n");
1156 our_current_position--;
1158 printf("SVA[P]P\tprev\n");
1159 if(!iterator.prev())
1160 return die_("iterator ended early\n");
1161 our_current_position--;
1163 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1164 if(!app->set_data(data, 32, true))
1165 return die_("setting APPLICATION data");
1166 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1167 return die_("copying object");
1168 if(!iterator.set_block(app, true))
1169 return die_ss_("iterator.set_block(app, true)", iterator);
1171 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1174 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1175 if(!app->set_data(data, 60, true))
1176 return die_("setting APPLICATION data");
1177 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1178 return die_("copying object");
1179 if(!iterator.set_block(app, true))
1180 return die_ss_("iterator.set_block(app, true)", iterator);
1182 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1185 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1186 if(!app->set_data(data, 87, true))
1187 return die_("setting APPLICATION data");
1188 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1189 return die_("copying object");
1190 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1191 if(!iterator.set_block(app, true))
1192 return die_ss_("iterator.set_block(app, true)", iterator);
1194 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1197 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1198 if(!app->set_data(data, 91, true))
1199 return die_("setting APPLICATION data");
1200 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1201 return die_("copying object");
1202 delete_from_our_metadata_(our_current_position+1);
1203 if(!iterator.set_block(app, true))
1204 return die_ss_("iterator.set_block(app, true)", iterator);
1206 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1209 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1210 if(!app->set_data(data, 100, true))
1211 return die_("setting APPLICATION data");
1212 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1213 return die_("copying object");
1214 delete_from_our_metadata_(our_current_position+1);
1215 our_metadata_.blocks[our_current_position]->set_is_last(true);
1216 if(!iterator.set_block(app, true))
1217 return die_ss_("iterator.set_block(app, true)", iterator);
1219 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1222 printf("SV[A]\tset PADDING (equal size)\n");
1223 padding->set_length(app->get_length());
1224 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1225 return die_("copying object");
1226 if(!iterator.set_block(padding, true))
1227 return die_ss_("iterator.set_block(padding, true)", iterator);
1229 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1232 printf("SV[P]\tinsert PADDING after\n");
1233 if(!iterator.insert_block_after(padding, false))
1234 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1235 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1238 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1241 printf("SVP[P]\tinsert PADDING after\n");
1242 padding->set_length(5);
1243 if(!iterator.insert_block_after(padding, false))
1244 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1245 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1248 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1251 printf("SVPP[P]\tprev\n");
1252 if(!iterator.prev())
1253 return die_("iterator ended early\n");
1254 our_current_position--;
1256 printf("SVP[P]P\tprev\n");
1257 if(!iterator.prev())
1258 return die_("iterator ended early\n");
1259 our_current_position--;
1261 printf("SV[P]PP\tprev\n");
1262 if(!iterator.prev())
1263 return die_("iterator ended early\n");
1264 our_current_position--;
1266 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1267 if(!app->set_data(data, 101, true))
1268 return die_("setting APPLICATION data");
1269 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1270 return die_("copying object");
1271 if(!iterator.insert_block_after(app, true))
1272 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1274 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1277 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1278 if(!iterator.delete_block(false))
1279 return die_ss_("iterator.delete_block(false)", iterator);
1280 delete_from_our_metadata_(our_current_position--);
1282 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1285 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1286 if(!app->set_data(data, 97, true))
1287 return die_("setting APPLICATION data");
1288 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1289 return die_("copying object");
1290 if(!iterator.insert_block_after(app, true))
1291 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1293 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1296 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1297 if(!iterator.delete_block(false))
1298 return die_ss_("iterator.delete_block(false)", iterator);
1299 delete_from_our_metadata_(our_current_position--);
1301 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1304 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1305 if(!app->set_data(data, 100, true))
1306 return die_("setting APPLICATION data");
1307 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1308 return die_("copying object");
1309 delete_from_our_metadata_(our_current_position+1);
1310 if(!iterator.insert_block_after(app, true))
1311 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1313 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1316 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1317 if(!iterator.delete_block(false))
1318 return die_ss_("iterator.delete_block(false)", iterator);
1319 delete_from_our_metadata_(our_current_position--);
1321 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1324 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1325 if(!app->set_data(data, 96, true))
1326 return die_("setting APPLICATION data");
1327 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1328 return die_("copying object");
1329 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1330 if(!iterator.insert_block_after(app, true))
1331 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1333 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1336 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1337 if(!iterator.delete_block(false))
1338 return die_ss_("iterator.delete_block(false)", iterator);
1339 delete_from_our_metadata_(our_current_position--);
1341 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1344 printf("S[V]PP\tnext\n");
1345 if(!iterator.next())
1346 return die_("iterator ended early\n");
1347 our_current_position++;
1349 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1350 if(!iterator.delete_block(false))
1351 return die_ss_("iterator.delete_block(false)", iterator);
1352 delete_from_our_metadata_(our_current_position--);
1354 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1357 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1358 if(!app->set_data(data, 1, true))
1359 return die_("setting APPLICATION data");
1360 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1361 return die_("copying object");
1362 delete_from_our_metadata_(our_current_position+1);
1363 if(!iterator.insert_block_after(app, true))
1364 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1366 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1373 if(!remove_file_(flacfile_))
1379 static bool test_level_2_(bool filename_based)
1381 FLAC::Metadata::Prototype *block;
1382 FLAC::Metadata::StreamInfo *streaminfo;
1383 FLAC::Metadata::Application *app;
1384 FLAC::Metadata::Padding *padding;
1385 FLAC__byte data[2000];
1386 unsigned our_current_position;
1388 // initialize 'data' to avoid Valgrind errors
1389 memset(data, 0, sizeof(data));
1391 printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1393 printf("generate read-only file\n");
1395 if(!generate_file_(/*include_cuesheet=*/false))
1398 if(!change_stats_(flacfile_, /*read_only=*/true))
1401 printf("create chain\n");
1402 FLAC::Metadata::Chain chain;
1403 if(!chain.is_valid())
1404 return die_("allocating memory for chain");
1406 printf("read chain\n");
1408 if(!read_chain_(chain, flacfile_, filename_based))
1409 return die_c_("reading chain", chain.status());
1411 printf("[S]VP\ttest initial metadata\n");
1413 if(!compare_chain_(chain, 0, 0))
1415 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1418 printf("switch file to read-write\n");
1420 if(!change_stats_(flacfile_, /*read-only=*/false))
1423 printf("create iterator\n");
1425 FLAC::Metadata::Iterator iterator;
1426 if(!iterator.is_valid())
1427 return die_("allocating memory for iterator");
1429 our_current_position = 0;
1431 iterator.init(chain);
1433 if(0 == (block = iterator.get_block()))
1434 return die_("getting block from iterator");
1436 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1438 printf("[S]VP\tmodify STREAMINFO, write\n");
1440 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1441 FLAC__ASSERT(0 != streaminfo);
1442 streaminfo->set_sample_rate(32000);
1443 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1444 return die_("copying object");
1447 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1448 return die_c_("during chain.write(false, true)", chain.status());
1449 block = iterator.get_block();
1450 if(!compare_chain_(chain, our_current_position, block))
1453 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1456 printf("[S]VP\tnext\n");
1457 if(!iterator.next())
1458 return die_("iterator ended early\n");
1459 our_current_position++;
1461 printf("S[V]P\tnext\n");
1462 if(!iterator.next())
1463 return die_("iterator ended early\n");
1464 our_current_position++;
1466 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1467 if(0 == (block = iterator.get_block()))
1468 return die_("getting block from iterator");
1469 if(0 == (app = new FLAC::Metadata::Application()))
1470 return die_("new FLAC::Metadata::Application()");
1471 app->set_id((const unsigned char *)"duh");
1472 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1473 return die_("setting APPLICATION data");
1475 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1476 return die_("copying object");
1477 if(!iterator.set_block(app))
1478 return die_c_("iterator.set_block(app)", chain.status());
1480 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1481 return die_c_("during chain.write(false, false)", chain.status());
1482 block = iterator.get_block();
1483 if(!compare_chain_(chain, our_current_position, block))
1486 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1489 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1490 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1491 return die_("copying object");
1492 if(!app->set_data(data, 26, true))
1493 return die_("setting APPLICATION data");
1494 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1495 return die_("copying object");
1496 if(!iterator.set_block(app))
1497 return die_c_("iterator.set_block(app)", chain.status());
1499 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1500 return die_c_("during chain.write(false, false)", chain.status());
1501 block = iterator.get_block();
1502 if(!compare_chain_(chain, our_current_position, block))
1505 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1508 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1509 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1510 return die_("copying object");
1511 if(!app->set_data(data, 28, true))
1512 return die_("setting APPLICATION data");
1513 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1514 return die_("copying object");
1515 if(!iterator.set_block(app))
1516 return die_c_("iterator.set_block(app)", chain.status());
1518 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1519 return die_c_("during chain.write(false, false)", chain.status());
1520 block = iterator.get_block();
1521 if(!compare_chain_(chain, our_current_position, block))
1524 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1527 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1528 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1529 return die_("copying object");
1530 if(!app->set_data(data, 36, true))
1531 return die_("setting APPLICATION data");
1532 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1533 return die_("copying object");
1534 if(!iterator.set_block(app))
1535 return die_c_("iterator.set_block(app)", chain.status());
1537 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1538 return die_c_("during chain.write(false, false)", chain.status());
1539 block = iterator.get_block();
1540 if(!compare_chain_(chain, our_current_position, block))
1543 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1546 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1547 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1548 return die_("copying object");
1549 if(!app->set_data(data, 33, true))
1550 return die_("setting APPLICATION data");
1551 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1552 return die_("copying object");
1553 if(!iterator.set_block(app))
1554 return die_c_("iterator.set_block(app)", chain.status());
1556 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1557 return die_c_("during chain.write(true, false)", chain.status());
1558 block = iterator.get_block();
1559 if(!compare_chain_(chain, our_current_position, block))
1562 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1565 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1566 if(0 == (padding = new FLAC::Metadata::Padding()))
1567 return die_("creating PADDING block");
1568 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1569 return die_("copying object");
1570 if(!app->set_data(data, 29, true))
1571 return die_("setting APPLICATION data");
1572 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1573 return die_("copying object");
1574 padding->set_length(0);
1575 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1576 return die_("internal error");
1577 if(!iterator.set_block(app))
1578 return die_c_("iterator.set_block(app)", chain.status());
1580 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1581 return die_c_("during chain.write(true, false)", chain.status());
1582 block = iterator.get_block();
1583 if(!compare_chain_(chain, our_current_position, block))
1586 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1589 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1590 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1591 return die_("copying object");
1592 if(!app->set_data(data, 16, true))
1593 return die_("setting APPLICATION data");
1594 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1595 return die_("copying object");
1596 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1597 if(!iterator.set_block(app))
1598 return die_c_("iterator.set_block(app)", chain.status());
1600 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1601 return die_c_("during chain.write(true, false)", chain.status());
1602 block = iterator.get_block();
1603 if(!compare_chain_(chain, our_current_position, block))
1606 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1609 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1610 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1611 return die_("copying object");
1612 if(!app->set_data(data, 50, true))
1613 return die_("setting APPLICATION data");
1614 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1615 return die_("copying object");
1616 if(!iterator.set_block(app))
1617 return die_c_("iterator.set_block(app)", chain.status());
1619 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1620 return die_c_("during chain.write(true, false)", chain.status());
1621 block = iterator.get_block();
1622 if(!compare_chain_(chain, our_current_position, block))
1625 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1628 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1629 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1630 return die_("copying object");
1631 if(!app->set_data(data, 56, true))
1632 return die_("setting APPLICATION data");
1633 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1634 return die_("copying object");
1635 add_to_padding_length_(our_current_position+1, -(56 - 50));
1636 if(!iterator.set_block(app))
1637 return die_c_("iterator.set_block(app)", chain.status());
1639 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1640 return die_c_("during chain.write(true, false)", chain.status());
1641 block = iterator.get_block();
1642 if(!compare_chain_(chain, our_current_position, block))
1645 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1648 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1649 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1650 return die_("copying object");
1651 if(!app->set_data(data, 67, true))
1652 return die_("setting APPLICATION data");
1653 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1654 return die_("copying object");
1655 delete_from_our_metadata_(our_current_position+1);
1656 if(!iterator.set_block(app))
1657 return die_c_("iterator.set_block(app)", chain.status());
1659 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1660 return die_c_("during chain.write(true, false)", chain.status());
1661 block = iterator.get_block();
1662 if(!compare_chain_(chain, our_current_position, block))
1665 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1668 printf("SV[A]\tprev\n");
1669 if(!iterator.prev())
1670 return die_("iterator ended early\n");
1671 our_current_position--;
1673 printf("S[V]A\tprev\n");
1674 if(!iterator.prev())
1675 return die_("iterator ended early\n");
1676 our_current_position--;
1678 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1679 if(0 == (padding = new FLAC::Metadata::Padding()))
1680 return die_("creating PADDING block");
1681 padding->set_length(30);
1682 if(!iterator.insert_block_before(padding))
1683 printf("\titerator.insert_block_before() returned false like it should\n");
1685 return die_("iterator.insert_block_before() should have returned false");
1687 printf("[S]VA\tnext\n");
1688 if(!iterator.next())
1689 return die_("iterator ended early\n");
1690 our_current_position++;
1692 printf("S[V]A\tinsert PADDING after\n");
1693 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1694 return die_("copying metadata");
1695 if(!iterator.insert_block_after(padding))
1696 return die_("iterator.insert_block_after(padding)");
1698 block = iterator.get_block();
1699 if(!compare_chain_(chain, our_current_position, block))
1703 printf("SV[P]A\tinsert PADDING before\n");
1704 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1705 return die_("creating PADDING block");
1706 padding->set_length(17);
1707 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1708 return die_("copying metadata");
1709 if(!iterator.insert_block_before(padding))
1710 return die_("iterator.insert_block_before(padding)");
1712 block = iterator.get_block();
1713 if(!compare_chain_(chain, our_current_position, block))
1717 printf("SV[P]PA\tinsert PADDING before\n");
1718 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1719 return die_("creating PADDING block");
1720 padding->set_length(0);
1721 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1722 return die_("copying metadata");
1723 if(!iterator.insert_block_before(padding))
1724 return die_("iterator.insert_block_before(padding)");
1726 block = iterator.get_block();
1727 if(!compare_chain_(chain, our_current_position, block))
1731 printf("SV[P]PPA\tnext\n");
1732 if(!iterator.next())
1733 return die_("iterator ended early\n");
1734 our_current_position++;
1736 printf("SVP[P]PA\tnext\n");
1737 if(!iterator.next())
1738 return die_("iterator ended early\n");
1739 our_current_position++;
1741 printf("SVPP[P]A\tnext\n");
1742 if(!iterator.next())
1743 return die_("iterator ended early\n");
1744 our_current_position++;
1746 printf("SVPPP[A]\tinsert PADDING after\n");
1747 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1748 return die_("creating PADDING block");
1749 padding->set_length(57);
1750 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1751 return die_("copying metadata");
1752 if(!iterator.insert_block_after(padding))
1753 return die_("iterator.insert_block_after(padding)");
1755 block = iterator.get_block();
1756 if(!compare_chain_(chain, our_current_position, block))
1760 printf("SVPPPA[P]\tinsert PADDING before\n");
1761 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1762 return die_("creating PADDING block");
1763 padding->set_length(99);
1764 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1765 return die_("copying metadata");
1766 if(!iterator.insert_block_before(padding))
1767 return die_("iterator.insert_block_before(padding)");
1769 block = iterator.get_block();
1770 if(!compare_chain_(chain, our_current_position, block))
1775 our_current_position = 0;
1777 printf("SVPPPAPP\tmerge padding\n");
1778 chain.merge_padding();
1779 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1780 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1781 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1782 delete_from_our_metadata_(7);
1783 delete_from_our_metadata_(4);
1784 delete_from_our_metadata_(3);
1786 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1787 return die_c_("during chain.write(true, false)", chain.status());
1788 if(!compare_chain_(chain, 0, 0))
1790 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1793 printf("SVPAP\tsort padding\n");
1794 chain.sort_padding();
1795 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1796 delete_from_our_metadata_(2);
1798 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1799 return die_c_("during chain.write(true, false)", chain.status());
1800 if(!compare_chain_(chain, 0, 0))
1802 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1805 printf("create iterator\n");
1807 FLAC::Metadata::Iterator iterator;
1808 if(!iterator.is_valid())
1809 return die_("allocating memory for iterator");
1811 our_current_position = 0;
1813 iterator.init(chain);
1815 printf("[S]VAP\tnext\n");
1816 if(!iterator.next())
1817 return die_("iterator ended early\n");
1818 our_current_position++;
1820 printf("S[V]AP\tnext\n");
1821 if(!iterator.next())
1822 return die_("iterator ended early\n");
1823 our_current_position++;
1825 printf("SV[A]P\tdelete middle block, replace with padding\n");
1826 if(0 == (padding = new FLAC::Metadata::Padding()))
1827 return die_("creating PADDING block");
1828 padding->set_length(71);
1829 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1830 return die_("copying object");
1831 if(!iterator.delete_block(/*replace_with_padding=*/true))
1832 return die_c_("iterator.delete_block(true)", chain.status());
1834 block = iterator.get_block();
1835 if(!compare_chain_(chain, our_current_position, block))
1839 printf("S[V]PP\tnext\n");
1840 if(!iterator.next())
1841 return die_("iterator ended early\n");
1842 our_current_position++;
1844 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1845 delete_from_our_metadata_(our_current_position--);
1846 if(!iterator.delete_block(/*replace_with_padding=*/false))
1847 return die_c_("iterator.delete_block(false)", chain.status());
1849 block = iterator.get_block();
1850 if(!compare_chain_(chain, our_current_position, block))
1854 printf("S[V]P\tnext\n");
1855 if(!iterator.next())
1856 return die_("iterator ended early\n");
1857 our_current_position++;
1859 printf("SV[P]\tdelete last block, replace with padding\n");
1860 if(0 == (padding = new FLAC::Metadata::Padding()))
1861 return die_("creating PADDING block");
1862 padding->set_length(219);
1863 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1864 return die_("copying object");
1865 if(!iterator.delete_block(/*replace_with_padding=*/true))
1866 return die_c_("iterator.delete_block(true)", chain.status());
1868 block = iterator.get_block();
1869 if(!compare_chain_(chain, our_current_position, block))
1873 printf("S[V]P\tnext\n");
1874 if(!iterator.next())
1875 return die_("iterator ended early\n");
1876 our_current_position++;
1878 printf("SV[P]\tdelete last block, don't replace with padding\n");
1879 delete_from_our_metadata_(our_current_position--);
1880 if(!iterator.delete_block(/*replace_with_padding=*/false))
1881 return die_c_("iterator.delete_block(false)", chain.status());
1883 block = iterator.get_block();
1884 if(!compare_chain_(chain, our_current_position, block))
1888 printf("S[V]\tprev\n");
1889 if(!iterator.prev())
1890 return die_("iterator ended early\n");
1891 our_current_position--;
1893 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1894 if(iterator.delete_block(/*replace_with_padding=*/false))
1895 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1897 block = iterator.get_block();
1898 if(!compare_chain_(chain, our_current_position, block))
1902 } // delete iterator
1903 our_current_position = 0;
1905 printf("SV\tmerge padding\n");
1906 chain.merge_padding();
1908 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1909 return die_c_("during chain.write(false, false)", chain.status());
1910 if(!compare_chain_(chain, 0, 0))
1912 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1915 printf("SV\tsort padding\n");
1916 chain.sort_padding();
1918 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1919 return die_c_("during chain.write(false, false)", chain.status());
1920 if(!compare_chain_(chain, 0, 0))
1922 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1925 if(!remove_file_(flacfile_))
1931 static bool test_level_2_misc_()
1933 ::FLAC__IOCallbacks callbacks;
1935 memset(&callbacks, 0, sizeof(callbacks));
1936 callbacks.read = (::FLAC__IOCallback_Read)fread;
1937 #ifdef FLAC__VALGRIND_TESTING
1938 callbacks.write = chain_write_cb_;
1940 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
1942 callbacks.seek = chain_seek_cb_;
1943 callbacks.tell = chain_tell_cb_;
1944 callbacks.eof = chain_eof_cb_;
1946 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1948 printf("generate file\n");
1950 if(!generate_file_(/*include_cuesheet=*/false))
1953 printf("create chain\n");
1954 FLAC::Metadata::Chain chain;
1955 if(!chain.is_valid())
1956 return die_("allocating chain");
1958 printf("read chain (filename-based)\n");
1960 if(!chain.read(flacfile_))
1961 return die_c_("reading chain", chain.status());
1963 printf("write chain with wrong method Chain::write(with callbacks)\n");
1965 if(chain.write(/*use_padding=*/false, 0, callbacks))
1966 return die_c_("mismatched write should have failed", chain.status());
1967 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1968 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
1969 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1972 printf("read chain (filename-based)\n");
1974 if(!chain.read(flacfile_))
1975 return die_c_("reading chain", chain.status());
1977 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
1979 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
1980 return die_c_("mismatched write should have failed", chain.status());
1981 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1982 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
1983 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1986 printf("read chain (callback-based)\n");
1988 FILE *file = fopen(flacfile_, "rb");
1990 return die_("opening file");
1991 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
1993 return die_c_("reading chain", chain.status());
1998 printf("write chain with wrong method write()\n");
2000 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2001 return die_c_("mismatched write should have failed", chain.status());
2002 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2003 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2004 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2007 printf("read chain (callback-based)\n");
2009 FILE *file = fopen(flacfile_, "rb");
2011 return die_("opening file");
2012 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2014 return die_c_("reading chain", chain.status());
2019 printf("testing Chain::check_if_tempfile_needed()... ");
2021 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2022 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2024 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2026 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2028 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2029 return die_c_("mismatched write should have failed", chain.status());
2030 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2031 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2032 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2035 printf("read chain (callback-based)\n");
2037 FILE *file = fopen(flacfile_, "rb");
2039 return die_("opening file");
2040 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2042 return die_c_("reading chain", chain.status());
2047 printf("create iterator\n");
2049 FLAC::Metadata::Iterator iterator;
2050 if(!iterator.is_valid())
2051 return die_("allocating memory for iterator");
2053 iterator.init(chain);
2055 printf("[S]VP\tnext\n");
2056 if(!iterator.next())
2057 return die_("iterator ended early\n");
2059 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2060 if(!iterator.delete_block(/*replace_with_padding=*/false))
2061 return die_c_("block delete failed\n", chain.status());
2063 printf("testing Chain::check_if_tempfile_needed()... ");
2065 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2066 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2068 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2070 printf("write chain with wrong method Chain::write(with callbacks)\n");
2072 if(chain.write(/*use_padding=*/false, 0, callbacks))
2073 return die_c_("mismatched write should have failed", chain.status());
2074 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2075 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2076 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2079 } // delete iterator
2081 if(!remove_file_(flacfile_))
2087 bool test_metadata_file_manipulation()
2089 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2091 our_metadata_.num_blocks = 0;
2093 if(!test_level_0_())
2096 if(!test_level_1_())
2099 if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2101 if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2103 if(!test_level_2_misc_())