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.
24 #include <stdlib.h> /* for malloc() */
25 #include <string.h> /* for memcpy()/memset() */
26 #if defined _MSC_VER || defined __MINGW32__
27 #include <sys/utime.h> /* for utime() */
28 #include <io.h> /* for chmod() */
29 #if _MSC_VER <= 1200 /* @@@ [2G limit] */
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() */
39 #include "FLAC/assert.h"
40 #include "FLAC++/decoder.h"
41 #include "FLAC++/metadata.h"
42 #include "share/grabbag.h"
44 #include "test_libs_common/file_utils_flac.h"
47 /******************************************************************************
48 The general strategy of these tests (for interface levels 1 and 2) is
49 to create a dummy FLAC file with a known set of initial metadata
50 blocks, then keep a mirror locally of what we expect the metadata to be
51 after each operation. Then testing becomes a simple matter of running
52 a FLAC::Decoder::File over the dummy file after each operation, comparing
53 the decoded metadata to what's in our local copy. If there are any
54 differences in the metadata, or the actual audio data is corrupted, we
55 will catch it while decoding.
56 ******************************************************************************/
58 class OurFileDecoder: public FLAC::Decoder::File {
60 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
62 bool ignore_metadata_;
65 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
66 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
67 void error_callback(::FLAC__StreamDecoderErrorStatus status);
71 FLAC::Metadata::Prototype *blocks[64];
75 static const char *flacfile_ = "metadata.flac";
77 /* our copy of the metadata in flacfile_ */
78 static OurMetadata our_metadata_;
80 /* the current block number that corresponds to the position of the iterator we are testing */
81 static unsigned mc_our_block_number_ = 0;
83 static bool die_(const char *msg)
85 printf("ERROR: %s\n", msg);
89 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
91 printf("ERROR: %s\n", msg);
92 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
96 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
98 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
99 printf("ERROR: %s\n", msg);
100 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
104 static void *malloc_or_die_(size_t size)
106 void *x = malloc(size);
108 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
114 static char *strdup_or_die_(const char *s)
118 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
124 /* functions for working with our metadata copy */
126 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
129 FLAC::Metadata::Prototype *obj = block;
130 FLAC__ASSERT(position < our_metadata_.num_blocks);
132 if(0 == (obj = FLAC::Metadata::clone(block)))
133 return die_("during FLAC::Metadata::clone()");
135 delete our_metadata_.blocks[position];
136 our_metadata_.blocks[position] = obj;
138 /* set the is_last flags */
139 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
140 our_metadata_.blocks[i]->set_is_last(false);
141 our_metadata_.blocks[i]->set_is_last(true);
146 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
149 FLAC::Metadata::Prototype *obj = block;
151 if(0 == (obj = FLAC::Metadata::clone(block)))
152 return die_("during FLAC::Metadata::clone()");
154 if(position > our_metadata_.num_blocks) {
155 position = our_metadata_.num_blocks;
158 for(i = our_metadata_.num_blocks; i > position; i--)
159 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
161 our_metadata_.blocks[position] = obj;
162 our_metadata_.num_blocks++;
164 /* set the is_last flags */
165 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
166 our_metadata_.blocks[i]->set_is_last(false);
167 our_metadata_.blocks[i]->set_is_last(true);
172 static void delete_from_our_metadata_(unsigned position)
175 FLAC__ASSERT(position < our_metadata_.num_blocks);
176 delete our_metadata_.blocks[position];
177 for(i = position; i < our_metadata_.num_blocks - 1; i++)
178 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
179 our_metadata_.num_blocks--;
181 /* set the is_last flags */
182 if(our_metadata_.num_blocks > 0) {
183 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
184 our_metadata_.blocks[i]->set_is_last(false);
185 our_metadata_.blocks[i]->set_is_last(true);
189 void add_to_padding_length_(unsigned index, int delta)
191 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
192 FLAC__ASSERT(0 != padding);
193 padding->set_length((unsigned)((int)padding->get_length() + delta));
197 * This wad of functions supports filename- and callback-based chain reading/writing.
198 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
200 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
202 static const char *tempfile_suffix = ".metadata_edit";
204 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
206 strcpy(*tempfilename, filename);
207 strcat(*tempfilename, tempfile_suffix);
209 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
215 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
218 (void)fclose(*tempfile);
222 if(0 != *tempfilename) {
223 (void)unlink(*tempfilename);
229 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
231 FLAC__ASSERT(0 != filename);
232 FLAC__ASSERT(0 != tempfile);
233 FLAC__ASSERT(0 != tempfilename);
234 FLAC__ASSERT(0 != *tempfilename);
237 (void)fclose(*tempfile);
241 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
242 /* on some flavors of windows, rename() will fail if the destination already exists */
243 if(unlink(filename) < 0) {
244 cleanup_tempfile_(tempfile, tempfilename);
249 if(0 != rename(*tempfilename, filename)) {
250 cleanup_tempfile_(tempfile, tempfilename);
254 cleanup_tempfile_(tempfile, tempfilename);
259 bool get_file_stats_(const char *filename, struct stat *stats)
261 FLAC__ASSERT(0 != filename);
262 FLAC__ASSERT(0 != stats);
263 return (0 == stat(filename, stats));
266 void set_file_stats_(const char *filename, struct stat *stats)
268 struct utimbuf srctime;
270 FLAC__ASSERT(0 != filename);
271 FLAC__ASSERT(0 != stats);
273 srctime.actime = stats->st_atime;
274 srctime.modtime = stats->st_mtime;
275 (void)chmod(filename, stats->st_mode);
276 (void)utime(filename, &srctime);
277 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
278 (void)chown(filename, stats->st_uid, (gid_t)(-1));
279 (void)chown(filename, (uid_t)(-1), stats->st_gid);
283 #ifdef FLAC__VALGRIND_TESTING
284 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
286 FILE *stream = (FILE*)handle;
287 size_t ret = fwrite(ptr, size, nmemb, stream);
294 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
296 off_t o = (off_t)offset;
297 FLAC__ASSERT(offset == o);
298 return fseeko((FILE*)handle, o, whence);
301 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
303 return ftello((FILE*)handle);
306 static int chain_eof_cb_(::FLAC__IOHandle handle)
308 return feof((FILE*)handle);
311 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
314 return chain.write(use_padding, preserve_file_stats);
316 ::FLAC__IOCallbacks callbacks;
318 memset(&callbacks, 0, sizeof(callbacks));
319 callbacks.read = (::FLAC__IOCallback_Read)fread;
320 #ifdef FLAC__VALGRIND_TESTING
321 callbacks.write = chain_write_cb_;
323 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
325 callbacks.seek = chain_seek_cb_;
326 callbacks.eof = chain_eof_cb_;
328 if(chain.check_if_tempfile_needed(use_padding)) {
330 FILE *file, *tempfile;
332 if(preserve_file_stats) {
333 if(!get_file_stats_(filename, &stats))
336 if(0 == (file = fopen(filename, "rb")))
337 return false; /*@@@@ chain status still says OK though */
338 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
340 cleanup_tempfile_(&tempfile, &tempfilename);
341 return false; /*@@@@ chain status still says OK though */
343 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
351 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
353 if(preserve_file_stats)
354 set_file_stats_(filename, &stats);
357 FILE *file = fopen(filename, "r+b");
359 return false; /*@@@@ chain status still says OK though */
360 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
369 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
372 return chain.read(filename);
374 ::FLAC__IOCallbacks callbacks;
376 memset(&callbacks, 0, sizeof(callbacks));
377 callbacks.read = (::FLAC__IOCallback_Read)fread;
378 callbacks.seek = chain_seek_cb_;
379 callbacks.tell = chain_tell_cb_;
383 FILE *file = fopen(filename, "rb");
385 return false; /*@@@@ chain status still says OK though */
386 ret = chain.read((::FLAC__IOHandle)file, callbacks);
393 /* function for comparing our metadata to a FLAC::Metadata::Chain */
395 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
398 FLAC::Metadata::Iterator iterator;
401 printf("\tcomparing chain... ");
404 if(!iterator.is_valid())
405 return die_("allocating memory for iterator");
407 iterator.init(chain);
411 FLAC::Metadata::Prototype *block;
416 if(0 == (block = iterator.get_block()))
417 return die_("getting block from iterator");
419 if(*block != *our_metadata_.blocks[i])
420 return die_("metadata block mismatch");
424 next_ok = iterator.next();
425 } while(i < our_metadata_.num_blocks && next_ok);
428 return die_("chain has more blocks than expected");
430 if(i < our_metadata_.num_blocks)
431 return die_("short block count in chain");
433 if(0 != current_block) {
434 printf("CURRENT_POSITION... ");
437 if(*current_block != *our_metadata_.blocks[current_position])
438 return die_("metadata block mismatch");
446 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
451 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
452 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
454 printf("content... ");
458 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
461 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
463 /* don't bother checking if we've already hit an error */
467 printf("%d... ", mc_our_block_number_);
470 if(!ignore_metadata_) {
471 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
472 (void)die_("got more metadata blocks than expected");
473 error_occurred_ = true;
476 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
477 (void)die_("metadata block mismatch");
478 error_occurred_ = true;
483 mc_our_block_number_++;
486 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
488 error_occurred_ = true;
489 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
492 static bool generate_file_(FLAC__bool include_extras)
494 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
495 ::FLAC__StreamMetadata *metadata[4];
496 unsigned i = 0, n = 0;
498 printf("generating FLAC file for test\n");
500 while(our_metadata_.num_blocks > 0)
501 delete_from_our_metadata_(0);
503 streaminfo.is_last = false;
504 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
505 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
506 streaminfo.data.stream_info.min_blocksize = 576;
507 streaminfo.data.stream_info.max_blocksize = 576;
508 streaminfo.data.stream_info.min_framesize = 0;
509 streaminfo.data.stream_info.max_framesize = 0;
510 streaminfo.data.stream_info.sample_rate = 44100;
511 streaminfo.data.stream_info.channels = 1;
512 streaminfo.data.stream_info.bits_per_sample = 8;
513 streaminfo.data.stream_info.total_samples = 0;
514 memset(streaminfo.data.stream_info.md5sum, 0, 16);
517 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
518 vorbiscomment.is_last = false;
519 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
520 vorbiscomment.length = (4 + vendor_string_length) + 4;
521 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
522 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
523 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
524 vorbiscomment.data.vorbis_comment.num_comments = 0;
525 vorbiscomment.data.vorbis_comment.comments = 0;
529 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
530 return die_("priming our metadata");
531 cuesheet->is_last = false;
532 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
533 cuesheet->data.cue_sheet.lead_in = 123;
534 cuesheet->data.cue_sheet.is_cd = false;
535 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
536 return die_("priming our metadata");
537 cuesheet->data.cue_sheet.tracks[0].number = 1;
538 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
539 return die_("priming our metadata");
543 picture.is_last = false;
544 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
547 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
548 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
549 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
550 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
551 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
552 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
553 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
554 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
557 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
558 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
559 picture.length += strlen(picture.data.picture.mime_type);
560 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
561 picture.length += strlen((const char *)picture.data.picture.description);
562 picture.data.picture.width = 300;
563 picture.data.picture.height = 300;
564 picture.data.picture.depth = 24;
565 picture.data.picture.colors = 0;
566 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
567 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
568 picture.length += picture.data.picture.data_length;
571 padding.is_last = true;
572 padding.type = ::FLAC__METADATA_TYPE_PADDING;
573 padding.length = 1234;
575 metadata[n++] = &vorbiscomment;
577 metadata[n++] = cuesheet;
578 metadata[n++] = &picture;
580 metadata[n++] = &padding;
582 FLAC::Metadata::StreamInfo s(&streaminfo);
583 FLAC::Metadata::VorbisComment v(&vorbiscomment);
584 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
585 FLAC::Metadata::Picture pi(&picture);
586 FLAC::Metadata::Padding p(&padding);
588 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
589 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
590 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
591 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
592 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
594 return die_("priming our metadata");
596 if(!file_utils__generate_flacfile(/*is_ogg=*/false, flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
597 return die_("creating the encoded file");
599 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
604 static bool test_file_(const char *filename, bool ignore_metadata)
606 OurFileDecoder decoder(ignore_metadata);
608 FLAC__ASSERT(0 != filename);
610 mc_our_block_number_ = 0;
611 decoder.error_occurred_ = false;
613 printf("\ttesting '%s'... ", filename);
616 if(!decoder.is_valid())
617 return die_("couldn't allocate decoder instance");
619 decoder.set_md5_checking(true);
620 decoder.set_metadata_respond_all();
621 if(decoder.init(filename) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
622 (void)decoder.finish();
623 return die_("initializing decoder\n");
625 if(!decoder.process_until_end_of_stream()) {
626 (void)decoder.finish();
627 return die_("decoding file\n");
630 (void)decoder.finish();
632 if(decoder.error_occurred_)
635 if(mc_our_block_number_ != our_metadata_.num_blocks)
636 return die_("short metadata block count");
642 static bool change_stats_(const char *filename, bool read_only)
644 if(!grabbag__file_change_stats(filename, read_only))
645 return die_("during grabbag__file_change_stats()");
650 static bool remove_file_(const char *filename)
652 while(our_metadata_.num_blocks > 0)
653 delete_from_our_metadata_(0);
655 if(!grabbag__file_remove_file(filename))
656 return die_("removing file");
661 static bool test_level_0_()
663 FLAC::Metadata::StreamInfo streaminfo;
665 printf("\n\n++++++ testing level 0 interface\n");
667 if(!generate_file_(/*include_extras=*/true))
670 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
673 printf("testing FLAC::Metadata::get_streaminfo()... ");
675 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
676 return die_("during FLAC::Metadata::get_streaminfo()");
678 /* check to see if some basic data matches (c.f. generate_file_()) */
679 if(streaminfo.get_channels() != 1)
680 return die_("mismatch in streaminfo.get_channels()");
681 if(streaminfo.get_bits_per_sample() != 8)
682 return die_("mismatch in streaminfo.get_bits_per_sample()");
683 if(streaminfo.get_sample_rate() != 44100)
684 return die_("mismatch in streaminfo.get_sample_rate()");
685 if(streaminfo.get_min_blocksize() != 576)
686 return die_("mismatch in streaminfo.get_min_blocksize()");
687 if(streaminfo.get_max_blocksize() != 576)
688 return die_("mismatch in streaminfo.get_max_blocksize()");
693 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
695 FLAC::Metadata::VorbisComment *tags = 0;
697 if(!FLAC::Metadata::get_tags(flacfile_, tags))
698 return die_("during FLAC::Metadata::get_tags()");
700 /* check to see if some basic data matches (c.f. generate_file_()) */
701 if(tags->get_num_comments() != 0)
702 return die_("mismatch in tags->get_num_comments()");
710 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
712 FLAC::Metadata::VorbisComment tags;
714 if(!FLAC::Metadata::get_tags(flacfile_, tags))
715 return die_("during FLAC::Metadata::get_tags()");
717 /* check to see if some basic data matches (c.f. generate_file_()) */
718 if(tags.get_num_comments() != 0)
719 return die_("mismatch in tags.get_num_comments()");
725 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
727 FLAC::Metadata::CueSheet *cuesheet = 0;
729 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
730 return die_("during FLAC::Metadata::get_cuesheet()");
732 /* check to see if some basic data matches (c.f. generate_file_()) */
733 if(cuesheet->get_lead_in() != 123)
734 return die_("mismatch in cuesheet->get_lead_in()");
742 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
744 FLAC::Metadata::CueSheet cuesheet;
746 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
747 return die_("during FLAC::Metadata::get_cuesheet()");
749 /* check to see if some basic data matches (c.f. generate_file_()) */
750 if(cuesheet.get_lead_in() != 123)
751 return die_("mismatch in cuesheet.get_lead_in()");
757 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
759 FLAC::Metadata::Picture *picture = 0;
761 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)))
762 return die_("during FLAC::Metadata::get_picture()");
764 /* check to see if some basic data matches (c.f. generate_file_()) */
765 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
766 return die_("mismatch in picture->get_type ()");
774 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
776 FLAC::Metadata::Picture picture;
778 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)))
779 return die_("during FLAC::Metadata::get_picture()");
781 /* check to see if some basic data matches (c.f. generate_file_()) */
782 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
783 return die_("mismatch in picture->get_type ()");
788 if(!remove_file_(flacfile_))
794 static bool test_level_1_()
796 FLAC::Metadata::Prototype *block;
797 FLAC::Metadata::StreamInfo *streaminfo;
798 FLAC::Metadata::Padding *padding;
799 FLAC::Metadata::Application *app;
800 FLAC__byte data[1000];
801 unsigned our_current_position = 0;
803 // initialize 'data' to avoid Valgrind errors
804 memset(data, 0, sizeof(data));
806 printf("\n\n++++++ testing level 1 interface\n");
808 /************************************************************/
810 printf("simple iterator on read-only file\n");
812 if(!generate_file_(/*include_extras=*/false))
815 if(!change_stats_(flacfile_, /*read_only=*/true))
818 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
821 FLAC::Metadata::SimpleIterator iterator;
823 if(!iterator.is_valid())
824 return die_("iterator.is_valid() returned false");
826 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
827 return die_("iterator.init() returned false");
829 printf("is writable = %u\n", (unsigned)iterator.is_writable());
830 if(iterator.is_writable())
831 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
833 printf("iterate forwards\n");
835 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
836 return die_("expected STREAMINFO type from iterator.get_block_type()");
837 if(0 == (block = iterator.get_block()))
838 return die_("getting block 0");
839 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
840 return die_("expected STREAMINFO type");
841 if(block->get_is_last())
842 return die_("expected is_last to be false");
843 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
844 return die_("bad STREAMINFO length");
845 /* check to see if some basic data matches (c.f. generate_file_()) */
846 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
847 FLAC__ASSERT(0 != streaminfo);
848 if(streaminfo->get_channels() != 1)
849 return die_("mismatch in channels");
850 if(streaminfo->get_bits_per_sample() != 8)
851 return die_("mismatch in bits_per_sample");
852 if(streaminfo->get_sample_rate() != 44100)
853 return die_("mismatch in sample_rate");
854 if(streaminfo->get_min_blocksize() != 576)
855 return die_("mismatch in min_blocksize");
856 if(streaminfo->get_max_blocksize() != 576)
857 return die_("mismatch in max_blocksize");
858 // we will delete streaminfo a little later when we're really done with it...
861 return die_("forward iterator ended early");
862 our_current_position++;
865 return die_("forward iterator ended early");
866 our_current_position++;
868 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
869 return die_("expected PADDING type from iterator.get_block_type()");
870 if(0 == (block = iterator.get_block()))
871 return die_("getting block 1");
872 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
873 return die_("expected PADDING type");
874 if(!block->get_is_last())
875 return die_("expected is_last to be true");
876 /* check to see if some basic data matches (c.f. generate_file_()) */
877 if(block->get_length() != 1234)
878 return die_("bad PADDING length");
882 return die_("forward iterator returned true but should have returned false");
884 printf("iterate backwards\n");
886 return die_("reverse iterator ended early");
888 return die_("reverse iterator ended early");
890 return die_("reverse iterator returned true but should have returned false");
892 printf("testing iterator.set_block() on read-only file...\n");
894 if(!iterator.set_block(streaminfo, false))
895 printf("PASSED. iterator.set_block() returned false like it should\n");
897 return die_("iterator.set_block() returned true but shouldn't have");
901 /************************************************************/
903 printf("simple iterator on writable file\n");
905 if(!change_stats_(flacfile_, /*read-only=*/false))
908 printf("creating APPLICATION block\n");
910 if(0 == (app = new FLAC::Metadata::Application()))
911 return die_("new FLAC::Metadata::Application()");
912 app->set_id((const unsigned char *)"duh");
914 printf("creating PADDING block\n");
916 if(0 == (padding = new FLAC::Metadata::Padding()))
917 return die_("new FLAC::Metadata::Padding()");
918 padding->set_length(20);
920 FLAC::Metadata::SimpleIterator iterator;
922 if(!iterator.is_valid())
923 return die_("iterator.is_valid() returned false");
925 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
926 return die_("iterator.init() returned false");
927 our_current_position = 0;
929 printf("is writable = %u\n", (unsigned)iterator.is_writable());
931 printf("[S]VP\ttry to write over STREAMINFO block...\n");
932 if(!iterator.set_block(app, false))
933 printf("\titerator.set_block() returned false like it should\n");
935 return die_("iterator.set_block() returned true but shouldn't have");
937 printf("[S]VP\tnext\n");
939 return die_("iterator ended early\n");
940 our_current_position++;
942 printf("S[V]P\tnext\n");
944 return die_("iterator ended early\n");
945 our_current_position++;
947 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
948 padding->set_length(25);
949 if(!iterator.insert_block_after(padding, false))
950 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
951 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
954 printf("SVP[P]\tprev\n");
956 return die_("iterator ended early\n");
957 our_current_position--;
959 printf("SV[P]P\tprev\n");
961 return die_("iterator ended early\n");
962 our_current_position--;
964 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
965 padding->set_length(30);
966 if(!iterator.insert_block_after(padding, false))
967 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
968 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
971 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
974 printf("SV[P]PP\tprev\n");
976 return die_("iterator ended early\n");
977 our_current_position--;
979 printf("S[V]PPP\tprev\n");
981 return die_("iterator ended early\n");
982 our_current_position--;
984 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
985 if(iterator.delete_block(false))
986 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
988 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
991 printf("[S]VPPP\tnext\n");
993 return die_("iterator ended early\n");
994 our_current_position++;
996 printf("S[V]PPP\tnext\n");
998 return die_("iterator ended early\n");
999 our_current_position++;
1001 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
1002 if(!iterator.delete_block(true))
1003 return die_ss_("iterator.delete_block(true)", iterator);
1004 our_current_position--;
1006 printf("S[V]PPP\tnext\n");
1007 if(!iterator.next())
1008 return die_("iterator ended early\n");
1009 our_current_position++;
1011 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1012 if(!iterator.delete_block(false))
1013 return die_ss_("iterator.delete_block(false)", iterator);
1014 delete_from_our_metadata_(our_current_position--);
1016 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1019 printf("S[V]PP\tnext\n");
1020 if(!iterator.next())
1021 return die_("iterator ended early\n");
1022 our_current_position++;
1024 printf("SV[P]P\tnext\n");
1025 if(!iterator.next())
1026 return die_("iterator ended early\n");
1027 our_current_position++;
1029 printf("SVP[P]\tdelete (last block), replace with padding\n");
1030 if(!iterator.delete_block(true))
1031 return die_ss_("iterator.delete_block(false)", iterator);
1032 our_current_position--;
1034 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1037 printf("SV[P]P\tnext\n");
1038 if(!iterator.next())
1039 return die_("iterator ended early\n");
1040 our_current_position++;
1042 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1043 if(!iterator.delete_block(false))
1044 return die_ss_("iterator.delete_block(false)", iterator);
1045 delete_from_our_metadata_(our_current_position--);
1047 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1050 printf("SV[P]\tprev\n");
1051 if(!iterator.prev())
1052 return die_("iterator ended early\n");
1053 our_current_position--;
1055 printf("S[V]P\tprev\n");
1056 if(!iterator.prev())
1057 return die_("iterator ended early\n");
1058 our_current_position--;
1060 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1061 FLAC__ASSERT(our_current_position == 0);
1062 block = iterator.get_block();
1063 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1064 FLAC__ASSERT(0 != streaminfo);
1065 streaminfo->set_sample_rate(32000);
1066 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1067 return die_("copying object");
1068 if(!iterator.set_block(block, false))
1069 return die_ss_("iterator.set_block(block, false)", iterator);
1072 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1075 printf("[S]VP\tnext\n");
1076 if(!iterator.next())
1077 return die_("iterator ended early\n");
1078 our_current_position++;
1080 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1081 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1082 if(!iterator.insert_block_after(app, true))
1083 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1084 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1086 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1088 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1091 printf("SV[A]P\tnext\n");
1092 if(!iterator.next())
1093 return die_("iterator ended early\n");
1094 our_current_position++;
1096 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1097 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1098 if(!iterator.set_block(app, true))
1099 return die_ss_("iterator.set_block(app, true)", iterator);
1100 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1102 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1104 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1107 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1108 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1109 if(!app->set_data(data, sizeof(data), true))
1110 return die_("setting APPLICATION data");
1111 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1112 return die_("copying object");
1113 if(!iterator.set_block(app, false))
1114 return die_ss_("iterator.set_block(app, false)", iterator);
1116 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1119 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1120 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1121 if(!app->set_data(data, 12, true))
1122 return die_("setting APPLICATION data");
1123 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1124 return die_("copying object");
1125 if(!iterator.set_block(app, false))
1126 return die_ss_("iterator.set_block(app, false)", iterator);
1128 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1131 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1132 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1133 if(!app->set_data(data, sizeof(data), true))
1134 return die_("setting APPLICATION data");
1135 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1136 return die_("copying object");
1137 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1138 if(!iterator.set_block(app, true))
1139 return die_ss_("iterator.set_block(app, true)", iterator);
1141 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1144 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1145 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1146 if(!app->set_data(data, 23, true))
1147 return die_("setting APPLICATION data");
1148 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1149 return die_("copying object");
1150 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1151 return die_("copying object");
1152 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1153 if(!iterator.set_block(app, true))
1154 return die_ss_("iterator.set_block(app, true)", iterator);
1156 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1159 printf("SVA[A]PP\tnext\n");
1160 if(!iterator.next())
1161 return die_("iterator ended early\n");
1162 our_current_position++;
1164 printf("SVAA[P]P\tnext\n");
1165 if(!iterator.next())
1166 return die_("iterator ended early\n");
1167 our_current_position++;
1169 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1170 padding->set_length(5);
1171 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1172 return die_("copying object");
1173 if(!iterator.set_block(padding, false))
1174 return die_ss_("iterator.set_block(padding, false)", iterator);
1176 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1179 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1180 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1181 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1182 return die_("copying object");
1183 if(!iterator.set_block(app, false))
1184 return die_ss_("iterator.set_block(app, false)", iterator);
1186 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1189 printf("SVAAP[A]\tset PADDING (equal)\n");
1190 padding->set_length(27);
1191 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1192 return die_("copying object");
1193 if(!iterator.set_block(padding, false))
1194 return die_ss_("iterator.set_block(padding, false)", iterator);
1196 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1199 printf("SVAAP[P]\tprev\n");
1200 if(!iterator.prev())
1201 return die_("iterator ended early\n");
1202 our_current_position--;
1204 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1205 if(!iterator.delete_block(false))
1206 return die_ss_("iterator.delete_block(false)", iterator);
1207 delete_from_our_metadata_(our_current_position--);
1209 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1212 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1213 if(!iterator.delete_block(false))
1214 return die_ss_("iterator.delete_block(false)", iterator);
1215 delete_from_our_metadata_(our_current_position--);
1217 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1220 printf("SV[A]P\tnext\n");
1221 if(!iterator.next())
1222 return die_("iterator ended early\n");
1223 our_current_position++;
1225 printf("SVA[P]\tinsert PADDING after\n");
1226 padding->set_length(5);
1227 if(!iterator.insert_block_after(padding, false))
1228 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1229 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1232 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1235 printf("SVAP[P]\tprev\n");
1236 if(!iterator.prev())
1237 return die_("iterator ended early\n");
1238 our_current_position--;
1240 printf("SVA[P]P\tprev\n");
1241 if(!iterator.prev())
1242 return die_("iterator ended early\n");
1243 our_current_position--;
1245 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1246 if(!app->set_data(data, 32, true))
1247 return die_("setting APPLICATION data");
1248 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1249 return die_("copying object");
1250 if(!iterator.set_block(app, true))
1251 return die_ss_("iterator.set_block(app, true)", iterator);
1253 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1256 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1257 if(!app->set_data(data, 60, true))
1258 return die_("setting APPLICATION data");
1259 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1260 return die_("copying object");
1261 if(!iterator.set_block(app, true))
1262 return die_ss_("iterator.set_block(app, true)", iterator);
1264 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1267 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1268 if(!app->set_data(data, 87, true))
1269 return die_("setting APPLICATION data");
1270 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1271 return die_("copying object");
1272 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1273 if(!iterator.set_block(app, true))
1274 return die_ss_("iterator.set_block(app, true)", iterator);
1276 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1279 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1280 if(!app->set_data(data, 91, true))
1281 return die_("setting APPLICATION data");
1282 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1283 return die_("copying object");
1284 delete_from_our_metadata_(our_current_position+1);
1285 if(!iterator.set_block(app, true))
1286 return die_ss_("iterator.set_block(app, true)", iterator);
1288 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1291 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1292 if(!app->set_data(data, 100, true))
1293 return die_("setting APPLICATION data");
1294 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1295 return die_("copying object");
1296 delete_from_our_metadata_(our_current_position+1);
1297 our_metadata_.blocks[our_current_position]->set_is_last(true);
1298 if(!iterator.set_block(app, true))
1299 return die_ss_("iterator.set_block(app, true)", iterator);
1301 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1304 printf("SV[A]\tset PADDING (equal size)\n");
1305 padding->set_length(app->get_length());
1306 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1307 return die_("copying object");
1308 if(!iterator.set_block(padding, true))
1309 return die_ss_("iterator.set_block(padding, true)", iterator);
1311 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1314 printf("SV[P]\tinsert PADDING after\n");
1315 if(!iterator.insert_block_after(padding, false))
1316 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1317 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1320 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1323 printf("SVP[P]\tinsert PADDING after\n");
1324 padding->set_length(5);
1325 if(!iterator.insert_block_after(padding, false))
1326 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1327 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1330 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1333 printf("SVPP[P]\tprev\n");
1334 if(!iterator.prev())
1335 return die_("iterator ended early\n");
1336 our_current_position--;
1338 printf("SVP[P]P\tprev\n");
1339 if(!iterator.prev())
1340 return die_("iterator ended early\n");
1341 our_current_position--;
1343 printf("SV[P]PP\tprev\n");
1344 if(!iterator.prev())
1345 return die_("iterator ended early\n");
1346 our_current_position--;
1348 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1349 if(!app->set_data(data, 101, true))
1350 return die_("setting APPLICATION data");
1351 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1352 return die_("copying object");
1353 if(!iterator.insert_block_after(app, true))
1354 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1356 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1359 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1360 if(!iterator.delete_block(false))
1361 return die_ss_("iterator.delete_block(false)", iterator);
1362 delete_from_our_metadata_(our_current_position--);
1364 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1367 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1368 if(!app->set_data(data, 97, true))
1369 return die_("setting APPLICATION data");
1370 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1371 return die_("copying object");
1372 if(!iterator.insert_block_after(app, true))
1373 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1375 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1378 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1379 if(!iterator.delete_block(false))
1380 return die_ss_("iterator.delete_block(false)", iterator);
1381 delete_from_our_metadata_(our_current_position--);
1383 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1386 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1387 if(!app->set_data(data, 100, true))
1388 return die_("setting APPLICATION data");
1389 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1390 return die_("copying object");
1391 delete_from_our_metadata_(our_current_position+1);
1392 if(!iterator.insert_block_after(app, true))
1393 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1395 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1398 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1399 if(!iterator.delete_block(false))
1400 return die_ss_("iterator.delete_block(false)", iterator);
1401 delete_from_our_metadata_(our_current_position--);
1403 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1406 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1407 if(!app->set_data(data, 96, true))
1408 return die_("setting APPLICATION data");
1409 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1410 return die_("copying object");
1411 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1412 if(!iterator.insert_block_after(app, true))
1413 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1415 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1418 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1419 if(!iterator.delete_block(false))
1420 return die_ss_("iterator.delete_block(false)", iterator);
1421 delete_from_our_metadata_(our_current_position--);
1423 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1426 printf("S[V]PP\tnext\n");
1427 if(!iterator.next())
1428 return die_("iterator ended early\n");
1429 our_current_position++;
1431 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1432 if(!iterator.delete_block(false))
1433 return die_ss_("iterator.delete_block(false)", iterator);
1434 delete_from_our_metadata_(our_current_position--);
1436 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1439 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1440 if(!app->set_data(data, 1, true))
1441 return die_("setting APPLICATION data");
1442 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1443 return die_("copying object");
1444 delete_from_our_metadata_(our_current_position+1);
1445 if(!iterator.insert_block_after(app, true))
1446 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1448 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1455 if(!remove_file_(flacfile_))
1461 static bool test_level_2_(bool filename_based)
1463 FLAC::Metadata::Prototype *block;
1464 FLAC::Metadata::StreamInfo *streaminfo;
1465 FLAC::Metadata::Application *app;
1466 FLAC::Metadata::Padding *padding;
1467 FLAC__byte data[2000];
1468 unsigned our_current_position;
1470 // initialize 'data' to avoid Valgrind errors
1471 memset(data, 0, sizeof(data));
1473 printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1475 printf("generate read-only file\n");
1477 if(!generate_file_(/*include_extras=*/false))
1480 if(!change_stats_(flacfile_, /*read_only=*/true))
1483 printf("create chain\n");
1484 FLAC::Metadata::Chain chain;
1485 if(!chain.is_valid())
1486 return die_("allocating memory for chain");
1488 printf("read chain\n");
1490 if(!read_chain_(chain, flacfile_, filename_based))
1491 return die_c_("reading chain", chain.status());
1493 printf("[S]VP\ttest initial metadata\n");
1495 if(!compare_chain_(chain, 0, 0))
1497 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1500 printf("switch file to read-write\n");
1502 if(!change_stats_(flacfile_, /*read-only=*/false))
1505 printf("create iterator\n");
1507 FLAC::Metadata::Iterator iterator;
1508 if(!iterator.is_valid())
1509 return die_("allocating memory for iterator");
1511 our_current_position = 0;
1513 iterator.init(chain);
1515 if(0 == (block = iterator.get_block()))
1516 return die_("getting block from iterator");
1518 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1520 printf("[S]VP\tmodify STREAMINFO, write\n");
1522 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1523 FLAC__ASSERT(0 != streaminfo);
1524 streaminfo->set_sample_rate(32000);
1525 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1526 return die_("copying object");
1529 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1530 return die_c_("during chain.write(false, true)", chain.status());
1531 block = iterator.get_block();
1532 if(!compare_chain_(chain, our_current_position, block))
1535 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1538 printf("[S]VP\tnext\n");
1539 if(!iterator.next())
1540 return die_("iterator ended early\n");
1541 our_current_position++;
1543 printf("S[V]P\tnext\n");
1544 if(!iterator.next())
1545 return die_("iterator ended early\n");
1546 our_current_position++;
1548 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1549 if(0 == (block = iterator.get_block()))
1550 return die_("getting block from iterator");
1551 if(0 == (app = new FLAC::Metadata::Application()))
1552 return die_("new FLAC::Metadata::Application()");
1553 app->set_id((const unsigned char *)"duh");
1554 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1555 return die_("setting APPLICATION data");
1557 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1558 return die_("copying object");
1559 if(!iterator.set_block(app))
1560 return die_c_("iterator.set_block(app)", chain.status());
1562 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1563 return die_c_("during chain.write(false, false)", chain.status());
1564 block = iterator.get_block();
1565 if(!compare_chain_(chain, our_current_position, block))
1568 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1571 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1572 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1573 return die_("copying object");
1574 if(!app->set_data(data, 26, true))
1575 return die_("setting APPLICATION data");
1576 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1577 return die_("copying object");
1578 if(!iterator.set_block(app))
1579 return die_c_("iterator.set_block(app)", chain.status());
1581 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1582 return die_c_("during chain.write(false, false)", chain.status());
1583 block = iterator.get_block();
1584 if(!compare_chain_(chain, our_current_position, block))
1587 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1590 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1591 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1592 return die_("copying object");
1593 if(!app->set_data(data, 28, true))
1594 return die_("setting APPLICATION data");
1595 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1596 return die_("copying object");
1597 if(!iterator.set_block(app))
1598 return die_c_("iterator.set_block(app)", chain.status());
1600 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1601 return die_c_("during chain.write(false, 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]\tgrow APPLICATION, use padding, but last block is not padding\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, 36, 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=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1620 return die_c_("during chain.write(false, 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]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\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, 33, 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 if(!iterator.set_block(app))
1636 return die_c_("iterator.set_block(app)", chain.status());
1638 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1639 return die_c_("during chain.write(true, false)", chain.status());
1640 block = iterator.get_block();
1641 if(!compare_chain_(chain, our_current_position, block))
1644 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1647 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1648 if(0 == (padding = new FLAC::Metadata::Padding()))
1649 return die_("creating PADDING block");
1650 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1651 return die_("copying object");
1652 if(!app->set_data(data, 29, true))
1653 return die_("setting APPLICATION data");
1654 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1655 return die_("copying object");
1656 padding->set_length(0);
1657 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1658 return die_("internal error");
1659 if(!iterator.set_block(app))
1660 return die_c_("iterator.set_block(app)", chain.status());
1662 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1663 return die_c_("during chain.write(true, false)", chain.status());
1664 block = iterator.get_block();
1665 if(!compare_chain_(chain, our_current_position, block))
1668 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1671 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1672 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1673 return die_("copying object");
1674 if(!app->set_data(data, 16, true))
1675 return die_("setting APPLICATION data");
1676 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1677 return die_("copying object");
1678 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1679 if(!iterator.set_block(app))
1680 return die_c_("iterator.set_block(app)", chain.status());
1682 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1683 return die_c_("during chain.write(true, false)", chain.status());
1684 block = iterator.get_block();
1685 if(!compare_chain_(chain, our_current_position, block))
1688 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1691 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1692 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1693 return die_("copying object");
1694 if(!app->set_data(data, 50, true))
1695 return die_("setting APPLICATION data");
1696 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1697 return die_("copying object");
1698 if(!iterator.set_block(app))
1699 return die_c_("iterator.set_block(app)", chain.status());
1701 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1702 return die_c_("during chain.write(true, false)", chain.status());
1703 block = iterator.get_block();
1704 if(!compare_chain_(chain, our_current_position, block))
1707 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1710 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1711 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1712 return die_("copying object");
1713 if(!app->set_data(data, 56, true))
1714 return die_("setting APPLICATION data");
1715 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1716 return die_("copying object");
1717 add_to_padding_length_(our_current_position+1, -(56 - 50));
1718 if(!iterator.set_block(app))
1719 return die_c_("iterator.set_block(app)", chain.status());
1721 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1722 return die_c_("during chain.write(true, false)", chain.status());
1723 block = iterator.get_block();
1724 if(!compare_chain_(chain, our_current_position, block))
1727 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1730 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1731 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1732 return die_("copying object");
1733 if(!app->set_data(data, 67, true))
1734 return die_("setting APPLICATION data");
1735 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1736 return die_("copying object");
1737 delete_from_our_metadata_(our_current_position+1);
1738 if(!iterator.set_block(app))
1739 return die_c_("iterator.set_block(app)", chain.status());
1741 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1742 return die_c_("during chain.write(true, false)", chain.status());
1743 block = iterator.get_block();
1744 if(!compare_chain_(chain, our_current_position, block))
1747 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1750 printf("SV[A]\tprev\n");
1751 if(!iterator.prev())
1752 return die_("iterator ended early\n");
1753 our_current_position--;
1755 printf("S[V]A\tprev\n");
1756 if(!iterator.prev())
1757 return die_("iterator ended early\n");
1758 our_current_position--;
1760 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1761 if(0 == (padding = new FLAC::Metadata::Padding()))
1762 return die_("creating PADDING block");
1763 padding->set_length(30);
1764 if(!iterator.insert_block_before(padding))
1765 printf("\titerator.insert_block_before() returned false like it should\n");
1767 return die_("iterator.insert_block_before() should have returned false");
1769 printf("[S]VA\tnext\n");
1770 if(!iterator.next())
1771 return die_("iterator ended early\n");
1772 our_current_position++;
1774 printf("S[V]A\tinsert PADDING after\n");
1775 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1776 return die_("copying metadata");
1777 if(!iterator.insert_block_after(padding))
1778 return die_("iterator.insert_block_after(padding)");
1780 block = iterator.get_block();
1781 if(!compare_chain_(chain, our_current_position, block))
1785 printf("SV[P]A\tinsert PADDING before\n");
1786 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1787 return die_("creating PADDING block");
1788 padding->set_length(17);
1789 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1790 return die_("copying metadata");
1791 if(!iterator.insert_block_before(padding))
1792 return die_("iterator.insert_block_before(padding)");
1794 block = iterator.get_block();
1795 if(!compare_chain_(chain, our_current_position, block))
1799 printf("SV[P]PA\tinsert PADDING before\n");
1800 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1801 return die_("creating PADDING block");
1802 padding->set_length(0);
1803 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1804 return die_("copying metadata");
1805 if(!iterator.insert_block_before(padding))
1806 return die_("iterator.insert_block_before(padding)");
1808 block = iterator.get_block();
1809 if(!compare_chain_(chain, our_current_position, block))
1813 printf("SV[P]PPA\tnext\n");
1814 if(!iterator.next())
1815 return die_("iterator ended early\n");
1816 our_current_position++;
1818 printf("SVP[P]PA\tnext\n");
1819 if(!iterator.next())
1820 return die_("iterator ended early\n");
1821 our_current_position++;
1823 printf("SVPP[P]A\tnext\n");
1824 if(!iterator.next())
1825 return die_("iterator ended early\n");
1826 our_current_position++;
1828 printf("SVPPP[A]\tinsert PADDING after\n");
1829 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1830 return die_("creating PADDING block");
1831 padding->set_length(57);
1832 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1833 return die_("copying metadata");
1834 if(!iterator.insert_block_after(padding))
1835 return die_("iterator.insert_block_after(padding)");
1837 block = iterator.get_block();
1838 if(!compare_chain_(chain, our_current_position, block))
1842 printf("SVPPPA[P]\tinsert PADDING before\n");
1843 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1844 return die_("creating PADDING block");
1845 padding->set_length(99);
1846 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1847 return die_("copying metadata");
1848 if(!iterator.insert_block_before(padding))
1849 return die_("iterator.insert_block_before(padding)");
1851 block = iterator.get_block();
1852 if(!compare_chain_(chain, our_current_position, block))
1857 our_current_position = 0;
1859 printf("SVPPPAPP\tmerge padding\n");
1860 chain.merge_padding();
1861 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1862 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1863 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1864 delete_from_our_metadata_(7);
1865 delete_from_our_metadata_(4);
1866 delete_from_our_metadata_(3);
1868 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1869 return die_c_("during chain.write(true, false)", chain.status());
1870 if(!compare_chain_(chain, 0, 0))
1872 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1875 printf("SVPAP\tsort padding\n");
1876 chain.sort_padding();
1877 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1878 delete_from_our_metadata_(2);
1880 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1881 return die_c_("during chain.write(true, false)", chain.status());
1882 if(!compare_chain_(chain, 0, 0))
1884 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1887 printf("create iterator\n");
1889 FLAC::Metadata::Iterator iterator;
1890 if(!iterator.is_valid())
1891 return die_("allocating memory for iterator");
1893 our_current_position = 0;
1895 iterator.init(chain);
1897 printf("[S]VAP\tnext\n");
1898 if(!iterator.next())
1899 return die_("iterator ended early\n");
1900 our_current_position++;
1902 printf("S[V]AP\tnext\n");
1903 if(!iterator.next())
1904 return die_("iterator ended early\n");
1905 our_current_position++;
1907 printf("SV[A]P\tdelete middle block, replace with padding\n");
1908 if(0 == (padding = new FLAC::Metadata::Padding()))
1909 return die_("creating PADDING block");
1910 padding->set_length(71);
1911 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1912 return die_("copying object");
1913 if(!iterator.delete_block(/*replace_with_padding=*/true))
1914 return die_c_("iterator.delete_block(true)", chain.status());
1916 block = iterator.get_block();
1917 if(!compare_chain_(chain, our_current_position, block))
1921 printf("S[V]PP\tnext\n");
1922 if(!iterator.next())
1923 return die_("iterator ended early\n");
1924 our_current_position++;
1926 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1927 delete_from_our_metadata_(our_current_position--);
1928 if(!iterator.delete_block(/*replace_with_padding=*/false))
1929 return die_c_("iterator.delete_block(false)", chain.status());
1931 block = iterator.get_block();
1932 if(!compare_chain_(chain, our_current_position, block))
1936 printf("S[V]P\tnext\n");
1937 if(!iterator.next())
1938 return die_("iterator ended early\n");
1939 our_current_position++;
1941 printf("SV[P]\tdelete last block, replace with padding\n");
1942 if(0 == (padding = new FLAC::Metadata::Padding()))
1943 return die_("creating PADDING block");
1944 padding->set_length(219);
1945 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1946 return die_("copying object");
1947 if(!iterator.delete_block(/*replace_with_padding=*/true))
1948 return die_c_("iterator.delete_block(true)", chain.status());
1950 block = iterator.get_block();
1951 if(!compare_chain_(chain, our_current_position, block))
1955 printf("S[V]P\tnext\n");
1956 if(!iterator.next())
1957 return die_("iterator ended early\n");
1958 our_current_position++;
1960 printf("SV[P]\tdelete last block, don't replace with padding\n");
1961 delete_from_our_metadata_(our_current_position--);
1962 if(!iterator.delete_block(/*replace_with_padding=*/false))
1963 return die_c_("iterator.delete_block(false)", chain.status());
1965 block = iterator.get_block();
1966 if(!compare_chain_(chain, our_current_position, block))
1970 printf("S[V]\tprev\n");
1971 if(!iterator.prev())
1972 return die_("iterator ended early\n");
1973 our_current_position--;
1975 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1976 if(iterator.delete_block(/*replace_with_padding=*/false))
1977 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1979 block = iterator.get_block();
1980 if(!compare_chain_(chain, our_current_position, block))
1984 } // delete iterator
1985 our_current_position = 0;
1987 printf("SV\tmerge padding\n");
1988 chain.merge_padding();
1990 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1991 return die_c_("during chain.write(false, false)", chain.status());
1992 if(!compare_chain_(chain, 0, 0))
1994 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1997 printf("SV\tsort padding\n");
1998 chain.sort_padding();
2000 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
2001 return die_c_("during chain.write(false, false)", chain.status());
2002 if(!compare_chain_(chain, 0, 0))
2004 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
2007 if(!remove_file_(flacfile_))
2013 static bool test_level_2_misc_()
2015 ::FLAC__IOCallbacks callbacks;
2017 memset(&callbacks, 0, sizeof(callbacks));
2018 callbacks.read = (::FLAC__IOCallback_Read)fread;
2019 #ifdef FLAC__VALGRIND_TESTING
2020 callbacks.write = chain_write_cb_;
2022 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2024 callbacks.seek = chain_seek_cb_;
2025 callbacks.tell = chain_tell_cb_;
2026 callbacks.eof = chain_eof_cb_;
2028 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2030 printf("generate file\n");
2032 if(!generate_file_(/*include_extras=*/false))
2035 printf("create chain\n");
2036 FLAC::Metadata::Chain chain;
2037 if(!chain.is_valid())
2038 return die_("allocating chain");
2040 printf("read chain (filename-based)\n");
2042 if(!chain.read(flacfile_))
2043 return die_c_("reading chain", chain.status());
2045 printf("write chain with wrong method Chain::write(with callbacks)\n");
2047 if(chain.write(/*use_padding=*/false, 0, callbacks))
2048 return die_c_("mismatched write should have failed", chain.status());
2049 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2050 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2051 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2054 printf("read chain (filename-based)\n");
2056 if(!chain.read(flacfile_))
2057 return die_c_("reading chain", chain.status());
2059 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2061 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2062 return die_c_("mismatched write should have failed", chain.status());
2063 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2064 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2065 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2068 printf("read chain (callback-based)\n");
2070 FILE *file = fopen(flacfile_, "rb");
2072 return die_("opening file");
2073 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2075 return die_c_("reading chain", chain.status());
2080 printf("write chain with wrong method write()\n");
2082 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2083 return die_c_("mismatched write should have failed", chain.status());
2084 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2085 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2086 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2089 printf("read chain (callback-based)\n");
2091 FILE *file = fopen(flacfile_, "rb");
2093 return die_("opening file");
2094 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2096 return die_c_("reading chain", chain.status());
2101 printf("testing Chain::check_if_tempfile_needed()... ");
2103 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2104 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2106 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2108 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2110 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2111 return die_c_("mismatched write should have failed", chain.status());
2112 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2113 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2114 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2117 printf("read chain (callback-based)\n");
2119 FILE *file = fopen(flacfile_, "rb");
2121 return die_("opening file");
2122 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2124 return die_c_("reading chain", chain.status());
2129 printf("create iterator\n");
2131 FLAC::Metadata::Iterator iterator;
2132 if(!iterator.is_valid())
2133 return die_("allocating memory for iterator");
2135 iterator.init(chain);
2137 printf("[S]VP\tnext\n");
2138 if(!iterator.next())
2139 return die_("iterator ended early\n");
2141 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2142 if(!iterator.delete_block(/*replace_with_padding=*/false))
2143 return die_c_("block delete failed\n", chain.status());
2145 printf("testing Chain::check_if_tempfile_needed()... ");
2147 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2148 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2150 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2152 printf("write chain with wrong method Chain::write(with callbacks)\n");
2154 if(chain.write(/*use_padding=*/false, 0, callbacks))
2155 return die_c_("mismatched write should have failed", chain.status());
2156 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2157 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2158 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2161 } // delete iterator
2163 if(!remove_file_(flacfile_))
2169 bool test_metadata_file_manipulation()
2171 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2173 our_metadata_.num_blocks = 0;
2175 if(!test_level_0_())
2178 if(!test_level_1_())
2181 if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2183 if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2185 if(!test_level_2_misc_())