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 #if _MSC_VER <= 1200 /* @@@ [2G limit] */
30 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
31 #include <utime.h> /* for utime() */
32 #include <unistd.h> /* for chown(), unlink() */
34 #include <sys/stat.h> /* for stat(), maybe chmod() */
35 #include "FLAC/assert.h"
36 #include "FLAC++/decoder.h"
37 #include "FLAC++/metadata.h"
38 #include "share/grabbag.h"
40 #include "test_libs_common/file_utils_flac.h"
43 /******************************************************************************
44 The general strategy of these tests (for interface levels 1 and 2) is
45 to create a dummy FLAC file with a known set of initial metadata
46 blocks, then keep a mirror locally of what we expect the metadata to be
47 after each operation. Then testing becomes a simple matter of running
48 a FLAC::Decoder::File over the dummy file after each operation, comparing
49 the decoded metadata to what's in our local copy. If there are any
50 differences in the metadata, or the actual audio data is corrupted, we
51 will catch it while decoding.
52 ******************************************************************************/
54 class OurFileDecoder: public FLAC::Decoder::File {
56 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
58 bool ignore_metadata_;
61 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
62 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
63 void error_callback(::FLAC__StreamDecoderErrorStatus status);
67 FLAC::Metadata::Prototype *blocks[64];
71 static const char *flacfile_ = "metadata.flac";
73 /* our copy of the metadata in flacfile_ */
74 static OurMetadata our_metadata_;
76 /* the current block number that corresponds to the position of the iterator we are testing */
77 static unsigned mc_our_block_number_ = 0;
79 static bool die_(const char *msg)
81 printf("ERROR: %s\n", msg);
85 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
87 printf("ERROR: %s\n", msg);
88 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
92 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
94 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
95 printf("ERROR: %s\n", msg);
96 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
100 static void *malloc_or_die_(size_t size)
102 void *x = malloc(size);
104 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
110 static char *strdup_or_die_(const char *s)
114 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
120 /* functions for working with our metadata copy */
122 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
125 FLAC::Metadata::Prototype *obj = block;
126 FLAC__ASSERT(position < our_metadata_.num_blocks);
128 if(0 == (obj = FLAC::Metadata::clone(block)))
129 return die_("during FLAC::Metadata::clone()");
131 delete our_metadata_.blocks[position];
132 our_metadata_.blocks[position] = obj;
134 /* set the is_last flags */
135 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
136 our_metadata_.blocks[i]->set_is_last(false);
137 our_metadata_.blocks[i]->set_is_last(true);
142 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
145 FLAC::Metadata::Prototype *obj = block;
147 if(0 == (obj = FLAC::Metadata::clone(block)))
148 return die_("during FLAC::Metadata::clone()");
150 if(position > our_metadata_.num_blocks) {
151 position = our_metadata_.num_blocks;
154 for(i = our_metadata_.num_blocks; i > position; i--)
155 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
157 our_metadata_.blocks[position] = obj;
158 our_metadata_.num_blocks++;
160 /* set the is_last flags */
161 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
162 our_metadata_.blocks[i]->set_is_last(false);
163 our_metadata_.blocks[i]->set_is_last(true);
168 static void delete_from_our_metadata_(unsigned position)
171 FLAC__ASSERT(position < our_metadata_.num_blocks);
172 delete our_metadata_.blocks[position];
173 for(i = position; i < our_metadata_.num_blocks - 1; i++)
174 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
175 our_metadata_.num_blocks--;
177 /* set the is_last flags */
178 if(our_metadata_.num_blocks > 0) {
179 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
180 our_metadata_.blocks[i]->set_is_last(false);
181 our_metadata_.blocks[i]->set_is_last(true);
185 void add_to_padding_length_(unsigned index, int delta)
187 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
188 FLAC__ASSERT(0 != padding);
189 padding->set_length((unsigned)((int)padding->get_length() + delta));
193 * This wad of functions supports filename- and callback-based chain reading/writing.
194 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
196 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
198 static const char *tempfile_suffix = ".metadata_edit";
200 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
202 strcpy(*tempfilename, filename);
203 strcat(*tempfilename, tempfile_suffix);
205 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
211 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
214 (void)fclose(*tempfile);
218 if(0 != *tempfilename) {
219 (void)unlink(*tempfilename);
225 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
227 FLAC__ASSERT(0 != filename);
228 FLAC__ASSERT(0 != tempfile);
229 FLAC__ASSERT(0 != tempfilename);
230 FLAC__ASSERT(0 != *tempfilename);
233 (void)fclose(*tempfile);
237 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
238 /* on some flavors of windows, rename() will fail if the destination already exists */
239 if(unlink(filename) < 0) {
240 cleanup_tempfile_(tempfile, tempfilename);
245 if(0 != rename(*tempfilename, filename)) {
246 cleanup_tempfile_(tempfile, tempfilename);
250 cleanup_tempfile_(tempfile, tempfilename);
255 bool get_file_stats_(const char *filename, struct stat *stats)
257 FLAC__ASSERT(0 != filename);
258 FLAC__ASSERT(0 != stats);
259 return (0 == stat(filename, stats));
262 void set_file_stats_(const char *filename, struct stat *stats)
264 struct utimbuf srctime;
266 FLAC__ASSERT(0 != filename);
267 FLAC__ASSERT(0 != stats);
269 srctime.actime = stats->st_atime;
270 srctime.modtime = stats->st_mtime;
271 (void)chmod(filename, stats->st_mode);
272 (void)utime(filename, &srctime);
273 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
274 (void)chown(filename, stats->st_uid, (gid_t)(-1));
275 (void)chown(filename, (uid_t)(-1), stats->st_gid);
279 #ifdef FLAC__VALGRIND_TESTING
280 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
282 FILE *stream = (FILE*)handle;
283 size_t ret = fwrite(ptr, size, nmemb, stream);
290 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
292 off_t o = (off_t)offset;
293 FLAC__ASSERT(offset == o);
294 return fseeko((FILE*)handle, o, whence);
297 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
299 return ftello((FILE*)handle);
302 static int chain_eof_cb_(::FLAC__IOHandle handle)
304 return feof((FILE*)handle);
307 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
310 return chain.write(use_padding, preserve_file_stats);
312 ::FLAC__IOCallbacks callbacks;
314 memset(&callbacks, 0, sizeof(callbacks));
315 callbacks.read = (::FLAC__IOCallback_Read)fread;
316 #ifdef FLAC__VALGRIND_TESTING
317 callbacks.write = chain_write_cb_;
319 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
321 callbacks.seek = chain_seek_cb_;
322 callbacks.eof = chain_eof_cb_;
324 if(chain.check_if_tempfile_needed(use_padding)) {
326 FILE *file, *tempfile;
328 if(preserve_file_stats) {
329 if(!get_file_stats_(filename, &stats))
332 if(0 == (file = fopen(filename, "rb")))
333 return false; /*@@@ chain status still says OK though */
334 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
336 cleanup_tempfile_(&tempfile, &tempfilename);
337 return false; /*@@@ chain status still says OK though */
339 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
347 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
349 if(preserve_file_stats)
350 set_file_stats_(filename, &stats);
353 FILE *file = fopen(filename, "r+b");
355 return false; /*@@@ chain status still says OK though */
356 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
365 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
368 return chain.read(filename);
370 ::FLAC__IOCallbacks callbacks;
372 memset(&callbacks, 0, sizeof(callbacks));
373 callbacks.read = (::FLAC__IOCallback_Read)fread;
374 callbacks.seek = chain_seek_cb_;
375 callbacks.tell = chain_tell_cb_;
379 FILE *file = fopen(filename, "rb");
381 return false; /*@@@ chain status still says OK though */
382 ret = chain.read((::FLAC__IOHandle)file, callbacks);
389 /* function for comparing our metadata to a FLAC::Metadata::Chain */
391 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
394 FLAC::Metadata::Iterator iterator;
397 printf("\tcomparing chain... ");
400 if(!iterator.is_valid())
401 return die_("allocating memory for iterator");
403 iterator.init(chain);
407 FLAC::Metadata::Prototype *block;
412 if(0 == (block = iterator.get_block()))
413 return die_("getting block from iterator");
415 if(*block != *our_metadata_.blocks[i])
416 return die_("metadata block mismatch");
420 next_ok = iterator.next();
421 } while(i < our_metadata_.num_blocks && next_ok);
424 return die_("chain has more blocks than expected");
426 if(i < our_metadata_.num_blocks)
427 return die_("short block count in chain");
429 if(0 != current_block) {
430 printf("CURRENT_POSITION... ");
433 if(*current_block != *our_metadata_.blocks[current_position])
434 return die_("metadata block mismatch");
442 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
447 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
448 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
450 printf("content... ");
454 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
457 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
459 /* don't bother checking if we've already hit an error */
463 printf("%d... ", mc_our_block_number_);
466 if(!ignore_metadata_) {
467 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
468 (void)die_("got more metadata blocks than expected");
469 error_occurred_ = true;
472 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
473 (void)die_("metadata block mismatch");
474 error_occurred_ = true;
479 mc_our_block_number_++;
482 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
484 error_occurred_ = true;
485 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
488 static bool generate_file_(FLAC__bool include_extras)
490 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
491 ::FLAC__StreamMetadata *metadata[4];
492 unsigned i = 0, n = 0;
494 printf("generating FLAC file for test\n");
496 while(our_metadata_.num_blocks > 0)
497 delete_from_our_metadata_(0);
499 streaminfo.is_last = false;
500 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
501 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
502 streaminfo.data.stream_info.min_blocksize = 576;
503 streaminfo.data.stream_info.max_blocksize = 576;
504 streaminfo.data.stream_info.min_framesize = 0;
505 streaminfo.data.stream_info.max_framesize = 0;
506 streaminfo.data.stream_info.sample_rate = 44100;
507 streaminfo.data.stream_info.channels = 1;
508 streaminfo.data.stream_info.bits_per_sample = 8;
509 streaminfo.data.stream_info.total_samples = 0;
510 memset(streaminfo.data.stream_info.md5sum, 0, 16);
513 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
514 vorbiscomment.is_last = false;
515 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
516 vorbiscomment.length = (4 + vendor_string_length) + 4;
517 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
518 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
519 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
520 vorbiscomment.data.vorbis_comment.num_comments = 0;
521 vorbiscomment.data.vorbis_comment.comments = 0;
525 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
526 return die_("priming our metadata");
527 cuesheet->is_last = false;
528 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
529 cuesheet->data.cue_sheet.lead_in = 123;
530 cuesheet->data.cue_sheet.is_cd = false;
531 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
532 return die_("priming our metadata");
533 cuesheet->data.cue_sheet.tracks[0].number = 1;
534 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
535 return die_("priming our metadata");
539 picture.is_last = false;
540 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
543 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
544 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
545 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
546 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
547 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
548 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
549 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
550 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
553 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
554 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
555 picture.length += strlen(picture.data.picture.mime_type);
556 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
557 picture.length += strlen((const char *)picture.data.picture.description);
558 picture.data.picture.width = 300;
559 picture.data.picture.height = 300;
560 picture.data.picture.depth = 24;
561 picture.data.picture.colors = 0;
562 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
563 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
564 picture.length += picture.data.picture.data_length;
567 padding.is_last = true;
568 padding.type = ::FLAC__METADATA_TYPE_PADDING;
569 padding.length = 1234;
571 metadata[n++] = &vorbiscomment;
573 metadata[n++] = cuesheet;
574 metadata[n++] = &picture;
576 metadata[n++] = &padding;
578 FLAC::Metadata::StreamInfo s(&streaminfo);
579 FLAC::Metadata::VorbisComment v(&vorbiscomment);
580 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
581 FLAC::Metadata::Picture pi(&picture);
582 FLAC::Metadata::Padding p(&padding);
584 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
585 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
586 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
587 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
588 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
590 return die_("priming our metadata");
592 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
593 return die_("creating the encoded file");
595 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
600 static bool test_file_(const char *filename, bool ignore_metadata)
602 OurFileDecoder decoder(ignore_metadata);
604 FLAC__ASSERT(0 != filename);
606 mc_our_block_number_ = 0;
607 decoder.error_occurred_ = false;
609 printf("\ttesting '%s'... ", filename);
612 if(!decoder.is_valid())
613 return die_("couldn't allocate decoder instance");
615 decoder.set_md5_checking(true);
616 decoder.set_metadata_respond_all();
617 if(decoder.init(filename) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
619 return die_("initializing decoder\n");
621 if(!decoder.process_until_end_of_stream()) {
623 return die_("decoding file\n");
628 if(decoder.error_occurred_)
631 if(mc_our_block_number_ != our_metadata_.num_blocks)
632 return die_("short metadata block count");
638 static bool change_stats_(const char *filename, bool read_only)
640 if(!grabbag__file_change_stats(filename, read_only))
641 return die_("during grabbag__file_change_stats()");
646 static bool remove_file_(const char *filename)
648 while(our_metadata_.num_blocks > 0)
649 delete_from_our_metadata_(0);
651 if(!grabbag__file_remove_file(filename))
652 return die_("removing file");
657 static bool test_level_0_()
659 FLAC::Metadata::StreamInfo streaminfo;
661 printf("\n\n++++++ testing level 0 interface\n");
663 if(!generate_file_(/*include_extras=*/true))
666 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
669 printf("testing FLAC::Metadata::get_streaminfo()... ");
671 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
672 return die_("during FLAC::Metadata::get_streaminfo()");
674 /* check to see if some basic data matches (c.f. generate_file_()) */
675 if(streaminfo.get_channels() != 1)
676 return die_("mismatch in streaminfo.get_channels()");
677 if(streaminfo.get_bits_per_sample() != 8)
678 return die_("mismatch in streaminfo.get_bits_per_sample()");
679 if(streaminfo.get_sample_rate() != 44100)
680 return die_("mismatch in streaminfo.get_sample_rate()");
681 if(streaminfo.get_min_blocksize() != 576)
682 return die_("mismatch in streaminfo.get_min_blocksize()");
683 if(streaminfo.get_max_blocksize() != 576)
684 return die_("mismatch in streaminfo.get_max_blocksize()");
689 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
691 FLAC::Metadata::VorbisComment *tags = 0;
693 if(!FLAC::Metadata::get_tags(flacfile_, tags))
694 return die_("during FLAC::Metadata::get_tags()");
696 /* check to see if some basic data matches (c.f. generate_file_()) */
697 if(tags->get_num_comments() != 0)
698 return die_("mismatch in tags->get_num_comments()");
706 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
708 FLAC::Metadata::VorbisComment tags;
710 if(!FLAC::Metadata::get_tags(flacfile_, tags))
711 return die_("during FLAC::Metadata::get_tags()");
713 /* check to see if some basic data matches (c.f. generate_file_()) */
714 if(tags.get_num_comments() != 0)
715 return die_("mismatch in tags.get_num_comments()");
721 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
723 FLAC::Metadata::CueSheet *cuesheet = 0;
725 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
726 return die_("during FLAC::Metadata::get_cuesheet()");
728 /* check to see if some basic data matches (c.f. generate_file_()) */
729 if(cuesheet->get_lead_in() != 123)
730 return die_("mismatch in cuesheet->get_lead_in()");
738 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
740 FLAC::Metadata::CueSheet cuesheet;
742 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
743 return die_("during FLAC::Metadata::get_cuesheet()");
745 /* check to see if some basic data matches (c.f. generate_file_()) */
746 if(cuesheet.get_lead_in() != 123)
747 return die_("mismatch in cuesheet.get_lead_in()");
753 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
755 FLAC::Metadata::Picture *picture = 0;
757 if(!FLAC::Metadata::get_picture(flacfile_, picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
758 return die_("during FLAC::Metadata::get_picture()");
760 /* check to see if some basic data matches (c.f. generate_file_()) */
761 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
762 return die_("mismatch in picture->get_type ()");
770 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
772 FLAC::Metadata::Picture picture;
774 if(!FLAC::Metadata::get_picture(flacfile_, picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
775 return die_("during FLAC::Metadata::get_picture()");
777 /* check to see if some basic data matches (c.f. generate_file_()) */
778 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
779 return die_("mismatch in picture->get_type ()");
784 if(!remove_file_(flacfile_))
790 static bool test_level_1_()
792 FLAC::Metadata::Prototype *block;
793 FLAC::Metadata::StreamInfo *streaminfo;
794 FLAC::Metadata::Padding *padding;
795 FLAC::Metadata::Application *app;
796 FLAC__byte data[1000];
797 unsigned our_current_position = 0;
799 // initialize 'data' to avoid Valgrind errors
800 memset(data, 0, sizeof(data));
802 printf("\n\n++++++ testing level 1 interface\n");
804 /************************************************************/
806 printf("simple iterator on read-only file\n");
808 if(!generate_file_(/*include_extras=*/false))
811 if(!change_stats_(flacfile_, /*read_only=*/true))
814 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
817 FLAC::Metadata::SimpleIterator iterator;
819 if(!iterator.is_valid())
820 return die_("iterator.is_valid() returned false");
822 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
823 return die_("iterator.init() returned false");
825 printf("is writable = %u\n", (unsigned)iterator.is_writable());
826 if(iterator.is_writable())
827 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
829 printf("iterate forwards\n");
831 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
832 return die_("expected STREAMINFO type from iterator.get_block_type()");
833 if(0 == (block = iterator.get_block()))
834 return die_("getting block 0");
835 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
836 return die_("expected STREAMINFO type");
837 if(block->get_is_last())
838 return die_("expected is_last to be false");
839 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
840 return die_("bad STREAMINFO length");
841 /* check to see if some basic data matches (c.f. generate_file_()) */
842 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
843 FLAC__ASSERT(0 != streaminfo);
844 if(streaminfo->get_channels() != 1)
845 return die_("mismatch in channels");
846 if(streaminfo->get_bits_per_sample() != 8)
847 return die_("mismatch in bits_per_sample");
848 if(streaminfo->get_sample_rate() != 44100)
849 return die_("mismatch in sample_rate");
850 if(streaminfo->get_min_blocksize() != 576)
851 return die_("mismatch in min_blocksize");
852 if(streaminfo->get_max_blocksize() != 576)
853 return die_("mismatch in max_blocksize");
854 // we will delete streaminfo a little later when we're really done with it...
857 return die_("forward iterator ended early");
858 our_current_position++;
861 return die_("forward iterator ended early");
862 our_current_position++;
864 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
865 return die_("expected PADDING type from iterator.get_block_type()");
866 if(0 == (block = iterator.get_block()))
867 return die_("getting block 1");
868 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
869 return die_("expected PADDING type");
870 if(!block->get_is_last())
871 return die_("expected is_last to be true");
872 /* check to see if some basic data matches (c.f. generate_file_()) */
873 if(block->get_length() != 1234)
874 return die_("bad PADDING length");
878 return die_("forward iterator returned true but should have returned false");
880 printf("iterate backwards\n");
882 return die_("reverse iterator ended early");
884 return die_("reverse iterator ended early");
886 return die_("reverse iterator returned true but should have returned false");
888 printf("testing iterator.set_block() on read-only file...\n");
890 if(!iterator.set_block(streaminfo, false))
891 printf("PASSED. iterator.set_block() returned false like it should\n");
893 return die_("iterator.set_block() returned true but shouldn't have");
897 /************************************************************/
899 printf("simple iterator on writable file\n");
901 if(!change_stats_(flacfile_, /*read-only=*/false))
904 printf("creating APPLICATION block\n");
906 if(0 == (app = new FLAC::Metadata::Application()))
907 return die_("new FLAC::Metadata::Application()");
908 app->set_id((const unsigned char *)"duh");
910 printf("creating PADDING block\n");
912 if(0 == (padding = new FLAC::Metadata::Padding()))
913 return die_("new FLAC::Metadata::Padding()");
914 padding->set_length(20);
916 FLAC::Metadata::SimpleIterator iterator;
918 if(!iterator.is_valid())
919 return die_("iterator.is_valid() returned false");
921 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
922 return die_("iterator.init() returned false");
923 our_current_position = 0;
925 printf("is writable = %u\n", (unsigned)iterator.is_writable());
927 printf("[S]VP\ttry to write over STREAMINFO block...\n");
928 if(!iterator.set_block(app, false))
929 printf("\titerator.set_block() returned false like it should\n");
931 return die_("iterator.set_block() returned true but shouldn't have");
933 printf("[S]VP\tnext\n");
935 return die_("iterator ended early\n");
936 our_current_position++;
938 printf("S[V]P\tnext\n");
940 return die_("iterator ended early\n");
941 our_current_position++;
943 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
944 padding->set_length(25);
945 if(!iterator.insert_block_after(padding, false))
946 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
947 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
950 printf("SVP[P]\tprev\n");
952 return die_("iterator ended early\n");
953 our_current_position--;
955 printf("SV[P]P\tprev\n");
957 return die_("iterator ended early\n");
958 our_current_position--;
960 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
961 padding->set_length(30);
962 if(!iterator.insert_block_after(padding, false))
963 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
964 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
967 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
970 printf("SV[P]PP\tprev\n");
972 return die_("iterator ended early\n");
973 our_current_position--;
975 printf("S[V]PPP\tprev\n");
977 return die_("iterator ended early\n");
978 our_current_position--;
980 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
981 if(iterator.delete_block(false))
982 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
984 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
987 printf("[S]VPPP\tnext\n");
989 return die_("iterator ended early\n");
990 our_current_position++;
992 printf("S[V]PPP\tnext\n");
994 return die_("iterator ended early\n");
995 our_current_position++;
997 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
998 if(!iterator.delete_block(true))
999 return die_ss_("iterator.delete_block(true)", iterator);
1000 our_current_position--;
1002 printf("S[V]PPP\tnext\n");
1003 if(!iterator.next())
1004 return die_("iterator ended early\n");
1005 our_current_position++;
1007 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1008 if(!iterator.delete_block(false))
1009 return die_ss_("iterator.delete_block(false)", iterator);
1010 delete_from_our_metadata_(our_current_position--);
1012 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1015 printf("S[V]PP\tnext\n");
1016 if(!iterator.next())
1017 return die_("iterator ended early\n");
1018 our_current_position++;
1020 printf("SV[P]P\tnext\n");
1021 if(!iterator.next())
1022 return die_("iterator ended early\n");
1023 our_current_position++;
1025 printf("SVP[P]\tdelete (last block), replace with padding\n");
1026 if(!iterator.delete_block(true))
1027 return die_ss_("iterator.delete_block(false)", iterator);
1028 our_current_position--;
1030 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1033 printf("SV[P]P\tnext\n");
1034 if(!iterator.next())
1035 return die_("iterator ended early\n");
1036 our_current_position++;
1038 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1039 if(!iterator.delete_block(false))
1040 return die_ss_("iterator.delete_block(false)", iterator);
1041 delete_from_our_metadata_(our_current_position--);
1043 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1046 printf("SV[P]\tprev\n");
1047 if(!iterator.prev())
1048 return die_("iterator ended early\n");
1049 our_current_position--;
1051 printf("S[V]P\tprev\n");
1052 if(!iterator.prev())
1053 return die_("iterator ended early\n");
1054 our_current_position--;
1056 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1057 FLAC__ASSERT(our_current_position == 0);
1058 block = iterator.get_block();
1059 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1060 FLAC__ASSERT(0 != streaminfo);
1061 streaminfo->set_sample_rate(32000);
1062 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1063 return die_("copying object");
1064 if(!iterator.set_block(block, false))
1065 return die_ss_("iterator.set_block(block, false)", iterator);
1068 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1071 printf("[S]VP\tnext\n");
1072 if(!iterator.next())
1073 return die_("iterator ended early\n");
1074 our_current_position++;
1076 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1077 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1078 if(!iterator.insert_block_after(app, true))
1079 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1080 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1082 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1084 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1087 printf("SV[A]P\tnext\n");
1088 if(!iterator.next())
1089 return die_("iterator ended early\n");
1090 our_current_position++;
1092 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1093 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1094 if(!iterator.set_block(app, true))
1095 return die_ss_("iterator.set_block(app, true)", iterator);
1096 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1098 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1100 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1103 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1104 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1105 if(!app->set_data(data, sizeof(data), true))
1106 return die_("setting APPLICATION data");
1107 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1108 return die_("copying object");
1109 if(!iterator.set_block(app, false))
1110 return die_ss_("iterator.set_block(app, false)", iterator);
1112 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1115 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1116 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1117 if(!app->set_data(data, 12, true))
1118 return die_("setting APPLICATION data");
1119 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1120 return die_("copying object");
1121 if(!iterator.set_block(app, false))
1122 return die_ss_("iterator.set_block(app, false)", iterator);
1124 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1127 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1128 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1129 if(!app->set_data(data, sizeof(data), true))
1130 return die_("setting APPLICATION data");
1131 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1132 return die_("copying object");
1133 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1134 if(!iterator.set_block(app, true))
1135 return die_ss_("iterator.set_block(app, true)", iterator);
1137 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1140 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1141 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1142 if(!app->set_data(data, 23, true))
1143 return die_("setting APPLICATION data");
1144 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1145 return die_("copying object");
1146 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1147 return die_("copying object");
1148 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1149 if(!iterator.set_block(app, true))
1150 return die_ss_("iterator.set_block(app, true)", iterator);
1152 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1155 printf("SVA[A]PP\tnext\n");
1156 if(!iterator.next())
1157 return die_("iterator ended early\n");
1158 our_current_position++;
1160 printf("SVAA[P]P\tnext\n");
1161 if(!iterator.next())
1162 return die_("iterator ended early\n");
1163 our_current_position++;
1165 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1166 padding->set_length(5);
1167 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1168 return die_("copying object");
1169 if(!iterator.set_block(padding, false))
1170 return die_ss_("iterator.set_block(padding, false)", iterator);
1172 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1175 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1176 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1177 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1178 return die_("copying object");
1179 if(!iterator.set_block(app, false))
1180 return die_ss_("iterator.set_block(app, false)", iterator);
1182 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1185 printf("SVAAP[A]\tset PADDING (equal)\n");
1186 padding->set_length(27);
1187 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1188 return die_("copying object");
1189 if(!iterator.set_block(padding, false))
1190 return die_ss_("iterator.set_block(padding, false)", iterator);
1192 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1195 printf("SVAAP[P]\tprev\n");
1196 if(!iterator.prev())
1197 return die_("iterator ended early\n");
1198 our_current_position--;
1200 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1201 if(!iterator.delete_block(false))
1202 return die_ss_("iterator.delete_block(false)", iterator);
1203 delete_from_our_metadata_(our_current_position--);
1205 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1208 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1209 if(!iterator.delete_block(false))
1210 return die_ss_("iterator.delete_block(false)", iterator);
1211 delete_from_our_metadata_(our_current_position--);
1213 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1216 printf("SV[A]P\tnext\n");
1217 if(!iterator.next())
1218 return die_("iterator ended early\n");
1219 our_current_position++;
1221 printf("SVA[P]\tinsert PADDING after\n");
1222 padding->set_length(5);
1223 if(!iterator.insert_block_after(padding, false))
1224 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1225 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1228 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1231 printf("SVAP[P]\tprev\n");
1232 if(!iterator.prev())
1233 return die_("iterator ended early\n");
1234 our_current_position--;
1236 printf("SVA[P]P\tprev\n");
1237 if(!iterator.prev())
1238 return die_("iterator ended early\n");
1239 our_current_position--;
1241 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1242 if(!app->set_data(data, 32, true))
1243 return die_("setting APPLICATION data");
1244 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1245 return die_("copying object");
1246 if(!iterator.set_block(app, true))
1247 return die_ss_("iterator.set_block(app, true)", iterator);
1249 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1252 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1253 if(!app->set_data(data, 60, true))
1254 return die_("setting APPLICATION data");
1255 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1256 return die_("copying object");
1257 if(!iterator.set_block(app, true))
1258 return die_ss_("iterator.set_block(app, true)", iterator);
1260 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1263 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1264 if(!app->set_data(data, 87, true))
1265 return die_("setting APPLICATION data");
1266 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1267 return die_("copying object");
1268 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1269 if(!iterator.set_block(app, true))
1270 return die_ss_("iterator.set_block(app, true)", iterator);
1272 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1275 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1276 if(!app->set_data(data, 91, true))
1277 return die_("setting APPLICATION data");
1278 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1279 return die_("copying object");
1280 delete_from_our_metadata_(our_current_position+1);
1281 if(!iterator.set_block(app, true))
1282 return die_ss_("iterator.set_block(app, true)", iterator);
1284 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1287 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1288 if(!app->set_data(data, 100, true))
1289 return die_("setting APPLICATION data");
1290 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1291 return die_("copying object");
1292 delete_from_our_metadata_(our_current_position+1);
1293 our_metadata_.blocks[our_current_position]->set_is_last(true);
1294 if(!iterator.set_block(app, true))
1295 return die_ss_("iterator.set_block(app, true)", iterator);
1297 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1300 printf("SV[A]\tset PADDING (equal size)\n");
1301 padding->set_length(app->get_length());
1302 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1303 return die_("copying object");
1304 if(!iterator.set_block(padding, true))
1305 return die_ss_("iterator.set_block(padding, true)", iterator);
1307 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1310 printf("SV[P]\tinsert PADDING after\n");
1311 if(!iterator.insert_block_after(padding, false))
1312 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1313 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1316 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1319 printf("SVP[P]\tinsert PADDING after\n");
1320 padding->set_length(5);
1321 if(!iterator.insert_block_after(padding, false))
1322 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1323 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1326 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1329 printf("SVPP[P]\tprev\n");
1330 if(!iterator.prev())
1331 return die_("iterator ended early\n");
1332 our_current_position--;
1334 printf("SVP[P]P\tprev\n");
1335 if(!iterator.prev())
1336 return die_("iterator ended early\n");
1337 our_current_position--;
1339 printf("SV[P]PP\tprev\n");
1340 if(!iterator.prev())
1341 return die_("iterator ended early\n");
1342 our_current_position--;
1344 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1345 if(!app->set_data(data, 101, true))
1346 return die_("setting APPLICATION data");
1347 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1348 return die_("copying object");
1349 if(!iterator.insert_block_after(app, true))
1350 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1352 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1355 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1356 if(!iterator.delete_block(false))
1357 return die_ss_("iterator.delete_block(false)", iterator);
1358 delete_from_our_metadata_(our_current_position--);
1360 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1363 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1364 if(!app->set_data(data, 97, true))
1365 return die_("setting APPLICATION data");
1366 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1367 return die_("copying object");
1368 if(!iterator.insert_block_after(app, true))
1369 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1371 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1374 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1375 if(!iterator.delete_block(false))
1376 return die_ss_("iterator.delete_block(false)", iterator);
1377 delete_from_our_metadata_(our_current_position--);
1379 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1382 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1383 if(!app->set_data(data, 100, true))
1384 return die_("setting APPLICATION data");
1385 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1386 return die_("copying object");
1387 delete_from_our_metadata_(our_current_position+1);
1388 if(!iterator.insert_block_after(app, true))
1389 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1391 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1394 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1395 if(!iterator.delete_block(false))
1396 return die_ss_("iterator.delete_block(false)", iterator);
1397 delete_from_our_metadata_(our_current_position--);
1399 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1402 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1403 if(!app->set_data(data, 96, true))
1404 return die_("setting APPLICATION data");
1405 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1406 return die_("copying object");
1407 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1408 if(!iterator.insert_block_after(app, true))
1409 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1411 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1414 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1415 if(!iterator.delete_block(false))
1416 return die_ss_("iterator.delete_block(false)", iterator);
1417 delete_from_our_metadata_(our_current_position--);
1419 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1422 printf("S[V]PP\tnext\n");
1423 if(!iterator.next())
1424 return die_("iterator ended early\n");
1425 our_current_position++;
1427 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1428 if(!iterator.delete_block(false))
1429 return die_ss_("iterator.delete_block(false)", iterator);
1430 delete_from_our_metadata_(our_current_position--);
1432 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1435 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1436 if(!app->set_data(data, 1, true))
1437 return die_("setting APPLICATION data");
1438 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1439 return die_("copying object");
1440 delete_from_our_metadata_(our_current_position+1);
1441 if(!iterator.insert_block_after(app, true))
1442 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1444 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1451 if(!remove_file_(flacfile_))
1457 static bool test_level_2_(bool filename_based)
1459 FLAC::Metadata::Prototype *block;
1460 FLAC::Metadata::StreamInfo *streaminfo;
1461 FLAC::Metadata::Application *app;
1462 FLAC::Metadata::Padding *padding;
1463 FLAC__byte data[2000];
1464 unsigned our_current_position;
1466 // initialize 'data' to avoid Valgrind errors
1467 memset(data, 0, sizeof(data));
1469 printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1471 printf("generate read-only file\n");
1473 if(!generate_file_(/*include_extras=*/false))
1476 if(!change_stats_(flacfile_, /*read_only=*/true))
1479 printf("create chain\n");
1480 FLAC::Metadata::Chain chain;
1481 if(!chain.is_valid())
1482 return die_("allocating memory for chain");
1484 printf("read chain\n");
1486 if(!read_chain_(chain, flacfile_, filename_based))
1487 return die_c_("reading chain", chain.status());
1489 printf("[S]VP\ttest initial metadata\n");
1491 if(!compare_chain_(chain, 0, 0))
1493 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1496 printf("switch file to read-write\n");
1498 if(!change_stats_(flacfile_, /*read-only=*/false))
1501 printf("create iterator\n");
1503 FLAC::Metadata::Iterator iterator;
1504 if(!iterator.is_valid())
1505 return die_("allocating memory for iterator");
1507 our_current_position = 0;
1509 iterator.init(chain);
1511 if(0 == (block = iterator.get_block()))
1512 return die_("getting block from iterator");
1514 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1516 printf("[S]VP\tmodify STREAMINFO, write\n");
1518 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1519 FLAC__ASSERT(0 != streaminfo);
1520 streaminfo->set_sample_rate(32000);
1521 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1522 return die_("copying object");
1525 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1526 return die_c_("during chain.write(false, true)", chain.status());
1527 block = iterator.get_block();
1528 if(!compare_chain_(chain, our_current_position, block))
1531 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1534 printf("[S]VP\tnext\n");
1535 if(!iterator.next())
1536 return die_("iterator ended early\n");
1537 our_current_position++;
1539 printf("S[V]P\tnext\n");
1540 if(!iterator.next())
1541 return die_("iterator ended early\n");
1542 our_current_position++;
1544 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1545 if(0 == (block = iterator.get_block()))
1546 return die_("getting block from iterator");
1547 if(0 == (app = new FLAC::Metadata::Application()))
1548 return die_("new FLAC::Metadata::Application()");
1549 app->set_id((const unsigned char *)"duh");
1550 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1551 return die_("setting APPLICATION data");
1553 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1554 return die_("copying object");
1555 if(!iterator.set_block(app))
1556 return die_c_("iterator.set_block(app)", chain.status());
1558 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1559 return die_c_("during chain.write(false, false)", chain.status());
1560 block = iterator.get_block();
1561 if(!compare_chain_(chain, our_current_position, block))
1564 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1567 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
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, 26, 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 if(!iterator.set_block(app))
1575 return die_c_("iterator.set_block(app)", chain.status());
1577 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1578 return die_c_("during chain.write(false, false)", chain.status());
1579 block = iterator.get_block();
1580 if(!compare_chain_(chain, our_current_position, block))
1583 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1586 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1587 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1588 return die_("copying object");
1589 if(!app->set_data(data, 28, true))
1590 return die_("setting APPLICATION data");
1591 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1592 return die_("copying object");
1593 if(!iterator.set_block(app))
1594 return die_c_("iterator.set_block(app)", chain.status());
1596 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1597 return die_c_("during chain.write(false, false)", chain.status());
1598 block = iterator.get_block();
1599 if(!compare_chain_(chain, our_current_position, block))
1602 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1605 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1606 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1607 return die_("copying object");
1608 if(!app->set_data(data, 36, true))
1609 return die_("setting APPLICATION data");
1610 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1611 return die_("copying object");
1612 if(!iterator.set_block(app))
1613 return die_c_("iterator.set_block(app)", chain.status());
1615 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1616 return die_c_("during chain.write(false, false)", chain.status());
1617 block = iterator.get_block();
1618 if(!compare_chain_(chain, our_current_position, block))
1621 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1624 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1625 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1626 return die_("copying object");
1627 if(!app->set_data(data, 33, true))
1628 return die_("setting APPLICATION data");
1629 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1630 return die_("copying object");
1631 if(!iterator.set_block(app))
1632 return die_c_("iterator.set_block(app)", chain.status());
1634 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1635 return die_c_("during chain.write(true, false)", chain.status());
1636 block = iterator.get_block();
1637 if(!compare_chain_(chain, our_current_position, block))
1640 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1643 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1644 if(0 == (padding = new FLAC::Metadata::Padding()))
1645 return die_("creating PADDING block");
1646 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1647 return die_("copying object");
1648 if(!app->set_data(data, 29, true))
1649 return die_("setting APPLICATION data");
1650 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1651 return die_("copying object");
1652 padding->set_length(0);
1653 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1654 return die_("internal error");
1655 if(!iterator.set_block(app))
1656 return die_c_("iterator.set_block(app)", chain.status());
1658 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1659 return die_c_("during chain.write(true, false)", chain.status());
1660 block = iterator.get_block();
1661 if(!compare_chain_(chain, our_current_position, block))
1664 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1667 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1668 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1669 return die_("copying object");
1670 if(!app->set_data(data, 16, true))
1671 return die_("setting APPLICATION data");
1672 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1673 return die_("copying object");
1674 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1675 if(!iterator.set_block(app))
1676 return die_c_("iterator.set_block(app)", chain.status());
1678 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1679 return die_c_("during chain.write(true, false)", chain.status());
1680 block = iterator.get_block();
1681 if(!compare_chain_(chain, our_current_position, block))
1684 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1687 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1688 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1689 return die_("copying object");
1690 if(!app->set_data(data, 50, true))
1691 return die_("setting APPLICATION data");
1692 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1693 return die_("copying object");
1694 if(!iterator.set_block(app))
1695 return die_c_("iterator.set_block(app)", chain.status());
1697 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1698 return die_c_("during chain.write(true, false)", chain.status());
1699 block = iterator.get_block();
1700 if(!compare_chain_(chain, our_current_position, block))
1703 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1706 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1707 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1708 return die_("copying object");
1709 if(!app->set_data(data, 56, true))
1710 return die_("setting APPLICATION data");
1711 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1712 return die_("copying object");
1713 add_to_padding_length_(our_current_position+1, -(56 - 50));
1714 if(!iterator.set_block(app))
1715 return die_c_("iterator.set_block(app)", chain.status());
1717 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1718 return die_c_("during chain.write(true, false)", chain.status());
1719 block = iterator.get_block();
1720 if(!compare_chain_(chain, our_current_position, block))
1723 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1726 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1727 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1728 return die_("copying object");
1729 if(!app->set_data(data, 67, true))
1730 return die_("setting APPLICATION data");
1731 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1732 return die_("copying object");
1733 delete_from_our_metadata_(our_current_position+1);
1734 if(!iterator.set_block(app))
1735 return die_c_("iterator.set_block(app)", chain.status());
1737 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1738 return die_c_("during chain.write(true, false)", chain.status());
1739 block = iterator.get_block();
1740 if(!compare_chain_(chain, our_current_position, block))
1743 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1746 printf("SV[A]\tprev\n");
1747 if(!iterator.prev())
1748 return die_("iterator ended early\n");
1749 our_current_position--;
1751 printf("S[V]A\tprev\n");
1752 if(!iterator.prev())
1753 return die_("iterator ended early\n");
1754 our_current_position--;
1756 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1757 if(0 == (padding = new FLAC::Metadata::Padding()))
1758 return die_("creating PADDING block");
1759 padding->set_length(30);
1760 if(!iterator.insert_block_before(padding))
1761 printf("\titerator.insert_block_before() returned false like it should\n");
1763 return die_("iterator.insert_block_before() should have returned false");
1765 printf("[S]VA\tnext\n");
1766 if(!iterator.next())
1767 return die_("iterator ended early\n");
1768 our_current_position++;
1770 printf("S[V]A\tinsert PADDING after\n");
1771 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1772 return die_("copying metadata");
1773 if(!iterator.insert_block_after(padding))
1774 return die_("iterator.insert_block_after(padding)");
1776 block = iterator.get_block();
1777 if(!compare_chain_(chain, our_current_position, block))
1781 printf("SV[P]A\tinsert PADDING before\n");
1782 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1783 return die_("creating PADDING block");
1784 padding->set_length(17);
1785 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1786 return die_("copying metadata");
1787 if(!iterator.insert_block_before(padding))
1788 return die_("iterator.insert_block_before(padding)");
1790 block = iterator.get_block();
1791 if(!compare_chain_(chain, our_current_position, block))
1795 printf("SV[P]PA\tinsert PADDING before\n");
1796 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1797 return die_("creating PADDING block");
1798 padding->set_length(0);
1799 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1800 return die_("copying metadata");
1801 if(!iterator.insert_block_before(padding))
1802 return die_("iterator.insert_block_before(padding)");
1804 block = iterator.get_block();
1805 if(!compare_chain_(chain, our_current_position, block))
1809 printf("SV[P]PPA\tnext\n");
1810 if(!iterator.next())
1811 return die_("iterator ended early\n");
1812 our_current_position++;
1814 printf("SVP[P]PA\tnext\n");
1815 if(!iterator.next())
1816 return die_("iterator ended early\n");
1817 our_current_position++;
1819 printf("SVPP[P]A\tnext\n");
1820 if(!iterator.next())
1821 return die_("iterator ended early\n");
1822 our_current_position++;
1824 printf("SVPPP[A]\tinsert PADDING after\n");
1825 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1826 return die_("creating PADDING block");
1827 padding->set_length(57);
1828 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1829 return die_("copying metadata");
1830 if(!iterator.insert_block_after(padding))
1831 return die_("iterator.insert_block_after(padding)");
1833 block = iterator.get_block();
1834 if(!compare_chain_(chain, our_current_position, block))
1838 printf("SVPPPA[P]\tinsert PADDING before\n");
1839 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1840 return die_("creating PADDING block");
1841 padding->set_length(99);
1842 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1843 return die_("copying metadata");
1844 if(!iterator.insert_block_before(padding))
1845 return die_("iterator.insert_block_before(padding)");
1847 block = iterator.get_block();
1848 if(!compare_chain_(chain, our_current_position, block))
1853 our_current_position = 0;
1855 printf("SVPPPAPP\tmerge padding\n");
1856 chain.merge_padding();
1857 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1858 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1859 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1860 delete_from_our_metadata_(7);
1861 delete_from_our_metadata_(4);
1862 delete_from_our_metadata_(3);
1864 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1865 return die_c_("during chain.write(true, false)", chain.status());
1866 if(!compare_chain_(chain, 0, 0))
1868 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1871 printf("SVPAP\tsort padding\n");
1872 chain.sort_padding();
1873 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1874 delete_from_our_metadata_(2);
1876 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1877 return die_c_("during chain.write(true, false)", chain.status());
1878 if(!compare_chain_(chain, 0, 0))
1880 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1883 printf("create iterator\n");
1885 FLAC::Metadata::Iterator iterator;
1886 if(!iterator.is_valid())
1887 return die_("allocating memory for iterator");
1889 our_current_position = 0;
1891 iterator.init(chain);
1893 printf("[S]VAP\tnext\n");
1894 if(!iterator.next())
1895 return die_("iterator ended early\n");
1896 our_current_position++;
1898 printf("S[V]AP\tnext\n");
1899 if(!iterator.next())
1900 return die_("iterator ended early\n");
1901 our_current_position++;
1903 printf("SV[A]P\tdelete middle block, replace with padding\n");
1904 if(0 == (padding = new FLAC::Metadata::Padding()))
1905 return die_("creating PADDING block");
1906 padding->set_length(71);
1907 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1908 return die_("copying object");
1909 if(!iterator.delete_block(/*replace_with_padding=*/true))
1910 return die_c_("iterator.delete_block(true)", chain.status());
1912 block = iterator.get_block();
1913 if(!compare_chain_(chain, our_current_position, block))
1917 printf("S[V]PP\tnext\n");
1918 if(!iterator.next())
1919 return die_("iterator ended early\n");
1920 our_current_position++;
1922 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1923 delete_from_our_metadata_(our_current_position--);
1924 if(!iterator.delete_block(/*replace_with_padding=*/false))
1925 return die_c_("iterator.delete_block(false)", chain.status());
1927 block = iterator.get_block();
1928 if(!compare_chain_(chain, our_current_position, block))
1932 printf("S[V]P\tnext\n");
1933 if(!iterator.next())
1934 return die_("iterator ended early\n");
1935 our_current_position++;
1937 printf("SV[P]\tdelete last block, replace with padding\n");
1938 if(0 == (padding = new FLAC::Metadata::Padding()))
1939 return die_("creating PADDING block");
1940 padding->set_length(219);
1941 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1942 return die_("copying object");
1943 if(!iterator.delete_block(/*replace_with_padding=*/true))
1944 return die_c_("iterator.delete_block(true)", chain.status());
1946 block = iterator.get_block();
1947 if(!compare_chain_(chain, our_current_position, block))
1951 printf("S[V]P\tnext\n");
1952 if(!iterator.next())
1953 return die_("iterator ended early\n");
1954 our_current_position++;
1956 printf("SV[P]\tdelete last block, don't replace with padding\n");
1957 delete_from_our_metadata_(our_current_position--);
1958 if(!iterator.delete_block(/*replace_with_padding=*/false))
1959 return die_c_("iterator.delete_block(false)", chain.status());
1961 block = iterator.get_block();
1962 if(!compare_chain_(chain, our_current_position, block))
1966 printf("S[V]\tprev\n");
1967 if(!iterator.prev())
1968 return die_("iterator ended early\n");
1969 our_current_position--;
1971 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1972 if(iterator.delete_block(/*replace_with_padding=*/false))
1973 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1975 block = iterator.get_block();
1976 if(!compare_chain_(chain, our_current_position, block))
1980 } // delete iterator
1981 our_current_position = 0;
1983 printf("SV\tmerge padding\n");
1984 chain.merge_padding();
1986 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1987 return die_c_("during chain.write(false, false)", chain.status());
1988 if(!compare_chain_(chain, 0, 0))
1990 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1993 printf("SV\tsort padding\n");
1994 chain.sort_padding();
1996 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1997 return die_c_("during chain.write(false, false)", chain.status());
1998 if(!compare_chain_(chain, 0, 0))
2000 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
2003 if(!remove_file_(flacfile_))
2009 static bool test_level_2_misc_()
2011 ::FLAC__IOCallbacks callbacks;
2013 memset(&callbacks, 0, sizeof(callbacks));
2014 callbacks.read = (::FLAC__IOCallback_Read)fread;
2015 #ifdef FLAC__VALGRIND_TESTING
2016 callbacks.write = chain_write_cb_;
2018 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2020 callbacks.seek = chain_seek_cb_;
2021 callbacks.tell = chain_tell_cb_;
2022 callbacks.eof = chain_eof_cb_;
2024 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2026 printf("generate file\n");
2028 if(!generate_file_(/*include_extras=*/false))
2031 printf("create chain\n");
2032 FLAC::Metadata::Chain chain;
2033 if(!chain.is_valid())
2034 return die_("allocating chain");
2036 printf("read chain (filename-based)\n");
2038 if(!chain.read(flacfile_))
2039 return die_c_("reading chain", chain.status());
2041 printf("write chain with wrong method Chain::write(with callbacks)\n");
2043 if(chain.write(/*use_padding=*/false, 0, callbacks))
2044 return die_c_("mismatched write should have failed", chain.status());
2045 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2046 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2047 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2050 printf("read chain (filename-based)\n");
2052 if(!chain.read(flacfile_))
2053 return die_c_("reading chain", chain.status());
2055 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2057 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2058 return die_c_("mismatched write should have failed", chain.status());
2059 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2060 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2061 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2064 printf("read chain (callback-based)\n");
2066 FILE *file = fopen(flacfile_, "rb");
2068 return die_("opening file");
2069 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2071 return die_c_("reading chain", chain.status());
2076 printf("write chain with wrong method write()\n");
2078 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2079 return die_c_("mismatched write should have failed", chain.status());
2080 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2081 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2082 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2085 printf("read chain (callback-based)\n");
2087 FILE *file = fopen(flacfile_, "rb");
2089 return die_("opening file");
2090 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2092 return die_c_("reading chain", chain.status());
2097 printf("testing Chain::check_if_tempfile_needed()... ");
2099 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2100 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2102 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2104 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2106 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2107 return die_c_("mismatched write should have failed", chain.status());
2108 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2109 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2110 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2113 printf("read chain (callback-based)\n");
2115 FILE *file = fopen(flacfile_, "rb");
2117 return die_("opening file");
2118 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2120 return die_c_("reading chain", chain.status());
2125 printf("create iterator\n");
2127 FLAC::Metadata::Iterator iterator;
2128 if(!iterator.is_valid())
2129 return die_("allocating memory for iterator");
2131 iterator.init(chain);
2133 printf("[S]VP\tnext\n");
2134 if(!iterator.next())
2135 return die_("iterator ended early\n");
2137 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2138 if(!iterator.delete_block(/*replace_with_padding=*/false))
2139 return die_c_("block delete failed\n", chain.status());
2141 printf("testing Chain::check_if_tempfile_needed()... ");
2143 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2144 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2146 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2148 printf("write chain with wrong method Chain::write(with callbacks)\n");
2150 if(chain.write(/*use_padding=*/false, 0, callbacks))
2151 return die_c_("mismatched write should have failed", chain.status());
2152 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2153 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2154 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2157 } // delete iterator
2159 if(!remove_file_(flacfile_))
2165 bool test_metadata_file_manipulation()
2167 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2169 our_metadata_.num_blocks = 0;
2171 if(!test_level_0_())
2174 if(!test_level_1_())
2177 if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2179 if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2181 if(!test_level_2_misc_())