1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <stdlib.h> /* for malloc() */
21 #include <string.h> /* for memcpy()/memset() */
22 #if defined _MSC_VER || defined __MINGW32__
23 #include <sys/utime.h> /* for utime() */
24 #include <io.h> /* for chmod() */
25 //@@@ [2G limit] hacks for MSVC6
29 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
30 #include <utime.h> /* for utime() */
31 #include <unistd.h> /* for chown(), unlink() */
33 #include <sys/stat.h> /* for stat(), maybe chmod() */
34 #include "FLAC/assert.h"
35 #include "FLAC++/decoder.h"
36 #include "FLAC++/metadata.h"
37 #include "share/grabbag.h"
39 #include "test_libs_common/file_utils_flac.h"
42 /******************************************************************************
43 The general strategy of these tests (for interface levels 1 and 2) is
44 to create a dummy FLAC file with a known set of initial metadata
45 blocks, then keep a mirror locally of what we expect the metadata to be
46 after each operation. Then testing becomes a simple matter of running
47 a FLAC::Decoder::File over the dummy file after each operation, comparing
48 the decoded metadata to what's in our local copy. If there are any
49 differences in the metadata, or the actual audio data is corrupted, we
50 will catch it while decoding.
51 ******************************************************************************/
53 class OurFileDecoder: public FLAC::Decoder::File {
55 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
57 bool ignore_metadata_;
60 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
61 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
62 void error_callback(::FLAC__StreamDecoderErrorStatus status);
66 FLAC::Metadata::Prototype *blocks[64];
70 static const char *flacfile_ = "metadata.flac";
72 /* our copy of the metadata in flacfile_ */
73 static OurMetadata our_metadata_;
75 /* the current block number that corresponds to the position of the iterator we are testing */
76 static unsigned mc_our_block_number_ = 0;
78 static bool die_(const char *msg)
80 printf("ERROR: %s\n", msg);
84 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
86 printf("ERROR: %s\n", msg);
87 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
91 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
93 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
94 printf("ERROR: %s\n", msg);
95 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
99 static void *malloc_or_die_(size_t size)
101 void *x = malloc(size);
103 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
109 static char *strdup_or_die_(const char *s)
113 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
119 /* functions for working with our metadata copy */
121 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
124 FLAC::Metadata::Prototype *obj = block;
125 FLAC__ASSERT(position < our_metadata_.num_blocks);
127 if(0 == (obj = FLAC::Metadata::clone(block)))
128 return die_("during FLAC::Metadata::clone()");
130 delete our_metadata_.blocks[position];
131 our_metadata_.blocks[position] = obj;
133 /* set the is_last flags */
134 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
135 our_metadata_.blocks[i]->set_is_last(false);
136 our_metadata_.blocks[i]->set_is_last(true);
141 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
144 FLAC::Metadata::Prototype *obj = block;
146 if(0 == (obj = FLAC::Metadata::clone(block)))
147 return die_("during FLAC::Metadata::clone()");
149 if(position > our_metadata_.num_blocks) {
150 position = our_metadata_.num_blocks;
153 for(i = our_metadata_.num_blocks; i > position; i--)
154 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
156 our_metadata_.blocks[position] = obj;
157 our_metadata_.num_blocks++;
159 /* set the is_last flags */
160 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
161 our_metadata_.blocks[i]->set_is_last(false);
162 our_metadata_.blocks[i]->set_is_last(true);
167 static void delete_from_our_metadata_(unsigned position)
170 FLAC__ASSERT(position < our_metadata_.num_blocks);
171 delete our_metadata_.blocks[position];
172 for(i = position; i < our_metadata_.num_blocks - 1; i++)
173 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
174 our_metadata_.num_blocks--;
176 /* set the is_last flags */
177 if(our_metadata_.num_blocks > 0) {
178 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
179 our_metadata_.blocks[i]->set_is_last(false);
180 our_metadata_.blocks[i]->set_is_last(true);
184 void add_to_padding_length_(unsigned index, int delta)
186 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
187 FLAC__ASSERT(0 != padding);
188 padding->set_length((unsigned)((int)padding->get_length() + delta));
192 * This wad of functions supports filename- and callback-based chain reading/writing.
193 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
195 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
197 static const char *tempfile_suffix = ".metadata_edit";
199 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
201 strcpy(*tempfilename, filename);
202 strcat(*tempfilename, tempfile_suffix);
204 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
210 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
213 (void)fclose(*tempfile);
217 if(0 != *tempfilename) {
218 (void)unlink(*tempfilename);
224 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
226 FLAC__ASSERT(0 != filename);
227 FLAC__ASSERT(0 != tempfile);
228 FLAC__ASSERT(0 != tempfilename);
229 FLAC__ASSERT(0 != *tempfilename);
232 (void)fclose(*tempfile);
236 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
237 /* on some flavors of windows, rename() will fail if the destination already exists */
238 if(unlink(filename) < 0) {
239 cleanup_tempfile_(tempfile, tempfilename);
244 if(0 != rename(*tempfilename, filename)) {
245 cleanup_tempfile_(tempfile, tempfilename);
249 cleanup_tempfile_(tempfile, tempfilename);
254 bool get_file_stats_(const char *filename, struct stat *stats)
256 FLAC__ASSERT(0 != filename);
257 FLAC__ASSERT(0 != stats);
258 return (0 == stat(filename, stats));
261 void set_file_stats_(const char *filename, struct stat *stats)
263 struct utimbuf srctime;
265 FLAC__ASSERT(0 != filename);
266 FLAC__ASSERT(0 != stats);
268 srctime.actime = stats->st_atime;
269 srctime.modtime = stats->st_mtime;
270 (void)chmod(filename, stats->st_mode);
271 (void)utime(filename, &srctime);
272 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
273 (void)chown(filename, stats->st_uid, (gid_t)(-1));
274 (void)chown(filename, (uid_t)(-1), stats->st_gid);
278 #ifdef FLAC__VALGRIND_TESTING
279 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
281 FILE *stream = (FILE*)handle;
282 size_t ret = fwrite(ptr, size, nmemb, stream);
289 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
291 off_t o = (off_t)offset;
292 FLAC__ASSERT(offset == o);
293 return fseeko((FILE*)handle, o, whence);
296 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
298 return ftello((FILE*)handle);
301 static int chain_eof_cb_(::FLAC__IOHandle handle)
303 return feof((FILE*)handle);
306 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
309 return chain.write(use_padding, preserve_file_stats);
311 ::FLAC__IOCallbacks callbacks;
313 memset(&callbacks, 0, sizeof(callbacks));
314 callbacks.read = (::FLAC__IOCallback_Read)fread;
315 #ifdef FLAC__VALGRIND_TESTING
316 callbacks.write = chain_write_cb_;
318 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
320 callbacks.seek = chain_seek_cb_;
321 callbacks.eof = chain_eof_cb_;
323 if(chain.check_if_tempfile_needed(use_padding)) {
325 FILE *file, *tempfile;
327 if(preserve_file_stats) {
328 if(!get_file_stats_(filename, &stats))
331 if(0 == (file = fopen(filename, "rb")))
332 return false; /*@@@ chain status still says OK though */
333 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
335 cleanup_tempfile_(&tempfile, &tempfilename);
336 return false; /*@@@ chain status still says OK though */
338 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
346 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
348 if(preserve_file_stats)
349 set_file_stats_(filename, &stats);
352 FILE *file = fopen(filename, "r+b");
354 return false; /*@@@ chain status still says OK though */
355 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
364 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
367 return chain.read(filename);
369 ::FLAC__IOCallbacks callbacks;
371 memset(&callbacks, 0, sizeof(callbacks));
372 callbacks.read = (::FLAC__IOCallback_Read)fread;
373 callbacks.seek = chain_seek_cb_;
374 callbacks.tell = chain_tell_cb_;
378 FILE *file = fopen(filename, "rb");
380 return false; /*@@@ chain status still says OK though */
381 ret = chain.read((::FLAC__IOHandle)file, callbacks);
388 /* function for comparing our metadata to a FLAC::Metadata::Chain */
390 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
393 FLAC::Metadata::Iterator iterator;
396 printf("\tcomparing chain... ");
399 if(!iterator.is_valid())
400 return die_("allocating memory for iterator");
402 iterator.init(chain);
406 FLAC::Metadata::Prototype *block;
411 if(0 == (block = iterator.get_block()))
412 return die_("getting block from iterator");
414 if(*block != *our_metadata_.blocks[i])
415 return die_("metadata block mismatch");
419 next_ok = iterator.next();
420 } while(i < our_metadata_.num_blocks && next_ok);
423 return die_("chain has more blocks than expected");
425 if(i < our_metadata_.num_blocks)
426 return die_("short block count in chain");
428 if(0 != current_block) {
429 printf("CURRENT_POSITION... ");
432 if(*current_block != *our_metadata_.blocks[current_position])
433 return die_("metadata block mismatch");
441 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
446 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
447 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
449 printf("content... ");
453 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
456 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
458 /* don't bother checking if we've already hit an error */
462 printf("%d... ", mc_our_block_number_);
465 if(!ignore_metadata_) {
466 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
467 (void)die_("got more metadata blocks than expected");
468 error_occurred_ = true;
471 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
472 (void)die_("metadata block mismatch");
473 error_occurred_ = true;
478 mc_our_block_number_++;
481 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
483 error_occurred_ = true;
484 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
487 static bool generate_file_(FLAC__bool include_extras)
489 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
490 ::FLAC__StreamMetadata *metadata[4];
491 unsigned i = 0, n = 0;
493 printf("generating FLAC file for test\n");
495 while(our_metadata_.num_blocks > 0)
496 delete_from_our_metadata_(0);
498 streaminfo.is_last = false;
499 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
500 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
501 streaminfo.data.stream_info.min_blocksize = 576;
502 streaminfo.data.stream_info.max_blocksize = 576;
503 streaminfo.data.stream_info.min_framesize = 0;
504 streaminfo.data.stream_info.max_framesize = 0;
505 streaminfo.data.stream_info.sample_rate = 44100;
506 streaminfo.data.stream_info.channels = 1;
507 streaminfo.data.stream_info.bits_per_sample = 8;
508 streaminfo.data.stream_info.total_samples = 0;
509 memset(streaminfo.data.stream_info.md5sum, 0, 16);
512 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
513 vorbiscomment.is_last = false;
514 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
515 vorbiscomment.length = (4 + vendor_string_length) + 4;
516 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
517 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
518 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
519 vorbiscomment.data.vorbis_comment.num_comments = 0;
520 vorbiscomment.data.vorbis_comment.comments = 0;
524 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
525 return die_("priming our metadata");
526 cuesheet->is_last = false;
527 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
528 cuesheet->data.cue_sheet.lead_in = 123;
529 cuesheet->data.cue_sheet.is_cd = false;
530 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
531 return die_("priming our metadata");
532 cuesheet->data.cue_sheet.tracks[0].number = 1;
533 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
534 return die_("priming our metadata");
538 picture.is_last = false;
539 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
542 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
543 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
544 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
545 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
546 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
547 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
548 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
551 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
552 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
553 picture.length += strlen(picture.data.picture.mime_type);
554 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
555 picture.length += strlen((const char *)picture.data.picture.description);
556 picture.data.picture.width = 300;
557 picture.data.picture.height = 300;
558 picture.data.picture.depth = 24;
559 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
560 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
561 picture.length += picture.data.picture.data_length;
564 padding.is_last = true;
565 padding.type = ::FLAC__METADATA_TYPE_PADDING;
566 padding.length = 1234;
568 metadata[n++] = &vorbiscomment;
570 metadata[n++] = cuesheet;
571 metadata[n++] = &picture;
573 metadata[n++] = &padding;
575 FLAC::Metadata::StreamInfo s(&streaminfo);
576 FLAC::Metadata::VorbisComment v(&vorbiscomment);
577 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
578 FLAC::Metadata::Picture pi(&picture);
579 FLAC::Metadata::Padding p(&padding);
581 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
582 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
583 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
584 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
585 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
587 return die_("priming our metadata");
589 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
590 return die_("creating the encoded file");
592 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
597 static bool test_file_(const char *filename, bool ignore_metadata)
599 OurFileDecoder decoder(ignore_metadata);
601 FLAC__ASSERT(0 != filename);
603 mc_our_block_number_ = 0;
604 decoder.error_occurred_ = false;
606 printf("\ttesting '%s'... ", filename);
609 if(!decoder.is_valid())
610 return die_("couldn't allocate decoder instance");
612 decoder.set_md5_checking(true);
613 decoder.set_metadata_respond_all();
614 if(decoder.init(filename) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
616 return die_("initializing decoder\n");
618 if(!decoder.process_until_end_of_stream()) {
620 return die_("decoding file\n");
625 if(decoder.error_occurred_)
628 if(mc_our_block_number_ != our_metadata_.num_blocks)
629 return die_("short metadata block count");
635 static bool change_stats_(const char *filename, bool read_only)
637 if(!grabbag__file_change_stats(filename, read_only))
638 return die_("during grabbag__file_change_stats()");
643 static bool remove_file_(const char *filename)
645 while(our_metadata_.num_blocks > 0)
646 delete_from_our_metadata_(0);
648 if(!grabbag__file_remove_file(filename))
649 return die_("removing file");
654 static bool test_level_0_()
656 FLAC::Metadata::StreamInfo streaminfo;
658 printf("\n\n++++++ testing level 0 interface\n");
660 if(!generate_file_(/*include_extras=*/true))
663 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
666 printf("testing FLAC::Metadata::get_streaminfo()... ");
668 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
669 return die_("during FLAC::Metadata::get_streaminfo()");
671 /* check to see if some basic data matches (c.f. generate_file_()) */
672 if(streaminfo.get_channels() != 1)
673 return die_("mismatch in streaminfo.get_channels()");
674 if(streaminfo.get_bits_per_sample() != 8)
675 return die_("mismatch in streaminfo.get_bits_per_sample()");
676 if(streaminfo.get_sample_rate() != 44100)
677 return die_("mismatch in streaminfo.get_sample_rate()");
678 if(streaminfo.get_min_blocksize() != 576)
679 return die_("mismatch in streaminfo.get_min_blocksize()");
680 if(streaminfo.get_max_blocksize() != 576)
681 return die_("mismatch in streaminfo.get_max_blocksize()");
686 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
688 FLAC::Metadata::VorbisComment *tags = 0;
690 if(!FLAC::Metadata::get_tags(flacfile_, tags))
691 return die_("during FLAC::Metadata::get_tags()");
693 /* check to see if some basic data matches (c.f. generate_file_()) */
694 if(tags->get_num_comments() != 0)
695 return die_("mismatch in tags->get_num_comments()");
703 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
705 FLAC::Metadata::VorbisComment tags;
707 if(!FLAC::Metadata::get_tags(flacfile_, tags))
708 return die_("during FLAC::Metadata::get_tags()");
710 /* check to see if some basic data matches (c.f. generate_file_()) */
711 if(tags.get_num_comments() != 0)
712 return die_("mismatch in tags.get_num_comments()");
718 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
720 FLAC::Metadata::CueSheet *cuesheet = 0;
722 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
723 return die_("during FLAC::Metadata::get_cuesheet()");
725 /* check to see if some basic data matches (c.f. generate_file_()) */
726 if(cuesheet->get_lead_in() != 123)
727 return die_("mismatch in cuesheet->get_lead_in()");
735 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
737 FLAC::Metadata::CueSheet cuesheet;
739 if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
740 return die_("during FLAC::Metadata::get_cuesheet()");
742 /* check to see if some basic data matches (c.f. generate_file_()) */
743 if(cuesheet.get_lead_in() != 123)
744 return die_("mismatch in cuesheet.get_lead_in()");
750 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
752 FLAC::Metadata::Picture *picture = 0;
754 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)))
755 return die_("during FLAC::Metadata::get_picture()");
757 /* check to see if some basic data matches (c.f. generate_file_()) */
758 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
759 return die_("mismatch in picture->get_type ()");
767 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
769 FLAC::Metadata::Picture picture;
771 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)))
772 return die_("during FLAC::Metadata::get_picture()");
774 /* check to see if some basic data matches (c.f. generate_file_()) */
775 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
776 return die_("mismatch in picture->get_type ()");
781 if(!remove_file_(flacfile_))
787 static bool test_level_1_()
789 FLAC::Metadata::Prototype *block;
790 FLAC::Metadata::StreamInfo *streaminfo;
791 FLAC::Metadata::Padding *padding;
792 FLAC::Metadata::Application *app;
793 FLAC__byte data[1000];
794 unsigned our_current_position = 0;
796 // initialize 'data' to avoid Valgrind errors
797 memset(data, 0, sizeof(data));
799 printf("\n\n++++++ testing level 1 interface\n");
801 /************************************************************/
803 printf("simple iterator on read-only file\n");
805 if(!generate_file_(/*include_extras=*/false))
808 if(!change_stats_(flacfile_, /*read_only=*/true))
811 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
814 FLAC::Metadata::SimpleIterator iterator;
816 if(!iterator.is_valid())
817 return die_("iterator.is_valid() returned false");
819 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
820 return die_("iterator.init() returned false");
822 printf("is writable = %u\n", (unsigned)iterator.is_writable());
823 if(iterator.is_writable())
824 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
826 printf("iterate forwards\n");
828 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
829 return die_("expected STREAMINFO type from iterator.get_block_type()");
830 if(0 == (block = iterator.get_block()))
831 return die_("getting block 0");
832 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
833 return die_("expected STREAMINFO type");
834 if(block->get_is_last())
835 return die_("expected is_last to be false");
836 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
837 return die_("bad STREAMINFO length");
838 /* check to see if some basic data matches (c.f. generate_file_()) */
839 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
840 FLAC__ASSERT(0 != streaminfo);
841 if(streaminfo->get_channels() != 1)
842 return die_("mismatch in channels");
843 if(streaminfo->get_bits_per_sample() != 8)
844 return die_("mismatch in bits_per_sample");
845 if(streaminfo->get_sample_rate() != 44100)
846 return die_("mismatch in sample_rate");
847 if(streaminfo->get_min_blocksize() != 576)
848 return die_("mismatch in min_blocksize");
849 if(streaminfo->get_max_blocksize() != 576)
850 return die_("mismatch in max_blocksize");
851 // we will delete streaminfo a little later when we're really done with it...
854 return die_("forward iterator ended early");
855 our_current_position++;
858 return die_("forward iterator ended early");
859 our_current_position++;
861 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
862 return die_("expected PADDING type from iterator.get_block_type()");
863 if(0 == (block = iterator.get_block()))
864 return die_("getting block 1");
865 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
866 return die_("expected PADDING type");
867 if(!block->get_is_last())
868 return die_("expected is_last to be true");
869 /* check to see if some basic data matches (c.f. generate_file_()) */
870 if(block->get_length() != 1234)
871 return die_("bad PADDING length");
875 return die_("forward iterator returned true but should have returned false");
877 printf("iterate backwards\n");
879 return die_("reverse iterator ended early");
881 return die_("reverse iterator ended early");
883 return die_("reverse iterator returned true but should have returned false");
885 printf("testing iterator.set_block() on read-only file...\n");
887 if(!iterator.set_block(streaminfo, false))
888 printf("PASSED. iterator.set_block() returned false like it should\n");
890 return die_("iterator.set_block() returned true but shouldn't have");
894 /************************************************************/
896 printf("simple iterator on writable file\n");
898 if(!change_stats_(flacfile_, /*read-only=*/false))
901 printf("creating APPLICATION block\n");
903 if(0 == (app = new FLAC::Metadata::Application()))
904 return die_("new FLAC::Metadata::Application()");
905 app->set_id((const unsigned char *)"duh");
907 printf("creating PADDING block\n");
909 if(0 == (padding = new FLAC::Metadata::Padding()))
910 return die_("new FLAC::Metadata::Padding()");
911 padding->set_length(20);
913 FLAC::Metadata::SimpleIterator iterator;
915 if(!iterator.is_valid())
916 return die_("iterator.is_valid() returned false");
918 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
919 return die_("iterator.init() returned false");
920 our_current_position = 0;
922 printf("is writable = %u\n", (unsigned)iterator.is_writable());
924 printf("[S]VP\ttry to write over STREAMINFO block...\n");
925 if(!iterator.set_block(app, false))
926 printf("\titerator.set_block() returned false like it should\n");
928 return die_("iterator.set_block() returned true but shouldn't have");
930 printf("[S]VP\tnext\n");
932 return die_("iterator ended early\n");
933 our_current_position++;
935 printf("S[V]P\tnext\n");
937 return die_("iterator ended early\n");
938 our_current_position++;
940 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
941 padding->set_length(25);
942 if(!iterator.insert_block_after(padding, false))
943 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
944 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
947 printf("SVP[P]\tprev\n");
949 return die_("iterator ended early\n");
950 our_current_position--;
952 printf("SV[P]P\tprev\n");
954 return die_("iterator ended early\n");
955 our_current_position--;
957 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
958 padding->set_length(30);
959 if(!iterator.insert_block_after(padding, false))
960 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
961 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
964 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
967 printf("SV[P]PP\tprev\n");
969 return die_("iterator ended early\n");
970 our_current_position--;
972 printf("S[V]PPP\tprev\n");
974 return die_("iterator ended early\n");
975 our_current_position--;
977 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
978 if(iterator.delete_block(false))
979 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
981 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
984 printf("[S]VPPP\tnext\n");
986 return die_("iterator ended early\n");
987 our_current_position++;
989 printf("S[V]PPP\tnext\n");
991 return die_("iterator ended early\n");
992 our_current_position++;
994 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
995 if(!iterator.delete_block(true))
996 return die_ss_("iterator.delete_block(true)", iterator);
997 our_current_position--;
999 printf("S[V]PPP\tnext\n");
1000 if(!iterator.next())
1001 return die_("iterator ended early\n");
1002 our_current_position++;
1004 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1005 if(!iterator.delete_block(false))
1006 return die_ss_("iterator.delete_block(false)", iterator);
1007 delete_from_our_metadata_(our_current_position--);
1009 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1012 printf("S[V]PP\tnext\n");
1013 if(!iterator.next())
1014 return die_("iterator ended early\n");
1015 our_current_position++;
1017 printf("SV[P]P\tnext\n");
1018 if(!iterator.next())
1019 return die_("iterator ended early\n");
1020 our_current_position++;
1022 printf("SVP[P]\tdelete (last block), replace with padding\n");
1023 if(!iterator.delete_block(true))
1024 return die_ss_("iterator.delete_block(false)", iterator);
1025 our_current_position--;
1027 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1030 printf("SV[P]P\tnext\n");
1031 if(!iterator.next())
1032 return die_("iterator ended early\n");
1033 our_current_position++;
1035 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1036 if(!iterator.delete_block(false))
1037 return die_ss_("iterator.delete_block(false)", iterator);
1038 delete_from_our_metadata_(our_current_position--);
1040 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1043 printf("SV[P]\tprev\n");
1044 if(!iterator.prev())
1045 return die_("iterator ended early\n");
1046 our_current_position--;
1048 printf("S[V]P\tprev\n");
1049 if(!iterator.prev())
1050 return die_("iterator ended early\n");
1051 our_current_position--;
1053 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1054 FLAC__ASSERT(our_current_position == 0);
1055 block = iterator.get_block();
1056 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1057 FLAC__ASSERT(0 != streaminfo);
1058 streaminfo->set_sample_rate(32000);
1059 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1060 return die_("copying object");
1061 if(!iterator.set_block(block, false))
1062 return die_ss_("iterator.set_block(block, false)", iterator);
1065 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1068 printf("[S]VP\tnext\n");
1069 if(!iterator.next())
1070 return die_("iterator ended early\n");
1071 our_current_position++;
1073 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1074 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1075 if(!iterator.insert_block_after(app, true))
1076 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1077 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1079 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1081 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1084 printf("SV[A]P\tnext\n");
1085 if(!iterator.next())
1086 return die_("iterator ended early\n");
1087 our_current_position++;
1089 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1090 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1091 if(!iterator.set_block(app, true))
1092 return die_ss_("iterator.set_block(app, true)", iterator);
1093 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1095 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1097 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1100 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1101 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1102 if(!app->set_data(data, sizeof(data), true))
1103 return die_("setting APPLICATION data");
1104 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1105 return die_("copying object");
1106 if(!iterator.set_block(app, false))
1107 return die_ss_("iterator.set_block(app, false)", iterator);
1109 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1112 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1113 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1114 if(!app->set_data(data, 12, true))
1115 return die_("setting APPLICATION data");
1116 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1117 return die_("copying object");
1118 if(!iterator.set_block(app, false))
1119 return die_ss_("iterator.set_block(app, false)", iterator);
1121 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1124 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1125 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1126 if(!app->set_data(data, sizeof(data), true))
1127 return die_("setting APPLICATION data");
1128 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1129 return die_("copying object");
1130 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1131 if(!iterator.set_block(app, true))
1132 return die_ss_("iterator.set_block(app, true)", iterator);
1134 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1137 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1138 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1139 if(!app->set_data(data, 23, true))
1140 return die_("setting APPLICATION data");
1141 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1142 return die_("copying object");
1143 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1144 return die_("copying object");
1145 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1146 if(!iterator.set_block(app, true))
1147 return die_ss_("iterator.set_block(app, true)", iterator);
1149 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1152 printf("SVA[A]PP\tnext\n");
1153 if(!iterator.next())
1154 return die_("iterator ended early\n");
1155 our_current_position++;
1157 printf("SVAA[P]P\tnext\n");
1158 if(!iterator.next())
1159 return die_("iterator ended early\n");
1160 our_current_position++;
1162 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1163 padding->set_length(5);
1164 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1165 return die_("copying object");
1166 if(!iterator.set_block(padding, false))
1167 return die_ss_("iterator.set_block(padding, false)", iterator);
1169 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1172 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1173 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1174 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1175 return die_("copying object");
1176 if(!iterator.set_block(app, false))
1177 return die_ss_("iterator.set_block(app, false)", iterator);
1179 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1182 printf("SVAAP[A]\tset PADDING (equal)\n");
1183 padding->set_length(27);
1184 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1185 return die_("copying object");
1186 if(!iterator.set_block(padding, false))
1187 return die_ss_("iterator.set_block(padding, false)", iterator);
1189 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1192 printf("SVAAP[P]\tprev\n");
1193 if(!iterator.prev())
1194 return die_("iterator ended early\n");
1195 our_current_position--;
1197 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1198 if(!iterator.delete_block(false))
1199 return die_ss_("iterator.delete_block(false)", iterator);
1200 delete_from_our_metadata_(our_current_position--);
1202 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1205 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1206 if(!iterator.delete_block(false))
1207 return die_ss_("iterator.delete_block(false)", iterator);
1208 delete_from_our_metadata_(our_current_position--);
1210 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1213 printf("SV[A]P\tnext\n");
1214 if(!iterator.next())
1215 return die_("iterator ended early\n");
1216 our_current_position++;
1218 printf("SVA[P]\tinsert PADDING after\n");
1219 padding->set_length(5);
1220 if(!iterator.insert_block_after(padding, false))
1221 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1222 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1225 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1228 printf("SVAP[P]\tprev\n");
1229 if(!iterator.prev())
1230 return die_("iterator ended early\n");
1231 our_current_position--;
1233 printf("SVA[P]P\tprev\n");
1234 if(!iterator.prev())
1235 return die_("iterator ended early\n");
1236 our_current_position--;
1238 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1239 if(!app->set_data(data, 32, true))
1240 return die_("setting APPLICATION data");
1241 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1242 return die_("copying object");
1243 if(!iterator.set_block(app, true))
1244 return die_ss_("iterator.set_block(app, true)", iterator);
1246 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1249 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1250 if(!app->set_data(data, 60, true))
1251 return die_("setting APPLICATION data");
1252 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1253 return die_("copying object");
1254 if(!iterator.set_block(app, true))
1255 return die_ss_("iterator.set_block(app, true)", iterator);
1257 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1260 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1261 if(!app->set_data(data, 87, true))
1262 return die_("setting APPLICATION data");
1263 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1264 return die_("copying object");
1265 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1266 if(!iterator.set_block(app, true))
1267 return die_ss_("iterator.set_block(app, true)", iterator);
1269 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1272 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1273 if(!app->set_data(data, 91, true))
1274 return die_("setting APPLICATION data");
1275 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1276 return die_("copying object");
1277 delete_from_our_metadata_(our_current_position+1);
1278 if(!iterator.set_block(app, true))
1279 return die_ss_("iterator.set_block(app, true)", iterator);
1281 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1284 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1285 if(!app->set_data(data, 100, true))
1286 return die_("setting APPLICATION data");
1287 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1288 return die_("copying object");
1289 delete_from_our_metadata_(our_current_position+1);
1290 our_metadata_.blocks[our_current_position]->set_is_last(true);
1291 if(!iterator.set_block(app, true))
1292 return die_ss_("iterator.set_block(app, true)", iterator);
1294 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1297 printf("SV[A]\tset PADDING (equal size)\n");
1298 padding->set_length(app->get_length());
1299 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1300 return die_("copying object");
1301 if(!iterator.set_block(padding, true))
1302 return die_ss_("iterator.set_block(padding, true)", iterator);
1304 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1307 printf("SV[P]\tinsert PADDING after\n");
1308 if(!iterator.insert_block_after(padding, false))
1309 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1310 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1313 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1316 printf("SVP[P]\tinsert PADDING after\n");
1317 padding->set_length(5);
1318 if(!iterator.insert_block_after(padding, false))
1319 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1320 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1323 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1326 printf("SVPP[P]\tprev\n");
1327 if(!iterator.prev())
1328 return die_("iterator ended early\n");
1329 our_current_position--;
1331 printf("SVP[P]P\tprev\n");
1332 if(!iterator.prev())
1333 return die_("iterator ended early\n");
1334 our_current_position--;
1336 printf("SV[P]PP\tprev\n");
1337 if(!iterator.prev())
1338 return die_("iterator ended early\n");
1339 our_current_position--;
1341 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1342 if(!app->set_data(data, 101, true))
1343 return die_("setting APPLICATION data");
1344 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1345 return die_("copying object");
1346 if(!iterator.insert_block_after(app, true))
1347 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1349 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1352 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1353 if(!iterator.delete_block(false))
1354 return die_ss_("iterator.delete_block(false)", iterator);
1355 delete_from_our_metadata_(our_current_position--);
1357 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1360 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1361 if(!app->set_data(data, 97, true))
1362 return die_("setting APPLICATION data");
1363 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1364 return die_("copying object");
1365 if(!iterator.insert_block_after(app, true))
1366 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1368 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1371 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1372 if(!iterator.delete_block(false))
1373 return die_ss_("iterator.delete_block(false)", iterator);
1374 delete_from_our_metadata_(our_current_position--);
1376 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1379 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1380 if(!app->set_data(data, 100, true))
1381 return die_("setting APPLICATION data");
1382 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1383 return die_("copying object");
1384 delete_from_our_metadata_(our_current_position+1);
1385 if(!iterator.insert_block_after(app, true))
1386 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1388 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1391 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1392 if(!iterator.delete_block(false))
1393 return die_ss_("iterator.delete_block(false)", iterator);
1394 delete_from_our_metadata_(our_current_position--);
1396 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1399 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1400 if(!app->set_data(data, 96, true))
1401 return die_("setting APPLICATION data");
1402 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1403 return die_("copying object");
1404 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1405 if(!iterator.insert_block_after(app, true))
1406 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1408 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1411 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1412 if(!iterator.delete_block(false))
1413 return die_ss_("iterator.delete_block(false)", iterator);
1414 delete_from_our_metadata_(our_current_position--);
1416 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1419 printf("S[V]PP\tnext\n");
1420 if(!iterator.next())
1421 return die_("iterator ended early\n");
1422 our_current_position++;
1424 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1425 if(!iterator.delete_block(false))
1426 return die_ss_("iterator.delete_block(false)", iterator);
1427 delete_from_our_metadata_(our_current_position--);
1429 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1432 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1433 if(!app->set_data(data, 1, true))
1434 return die_("setting APPLICATION data");
1435 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1436 return die_("copying object");
1437 delete_from_our_metadata_(our_current_position+1);
1438 if(!iterator.insert_block_after(app, true))
1439 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1441 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1448 if(!remove_file_(flacfile_))
1454 static bool test_level_2_(bool filename_based)
1456 FLAC::Metadata::Prototype *block;
1457 FLAC::Metadata::StreamInfo *streaminfo;
1458 FLAC::Metadata::Application *app;
1459 FLAC::Metadata::Padding *padding;
1460 FLAC__byte data[2000];
1461 unsigned our_current_position;
1463 // initialize 'data' to avoid Valgrind errors
1464 memset(data, 0, sizeof(data));
1466 printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1468 printf("generate read-only file\n");
1470 if(!generate_file_(/*include_extras=*/false))
1473 if(!change_stats_(flacfile_, /*read_only=*/true))
1476 printf("create chain\n");
1477 FLAC::Metadata::Chain chain;
1478 if(!chain.is_valid())
1479 return die_("allocating memory for chain");
1481 printf("read chain\n");
1483 if(!read_chain_(chain, flacfile_, filename_based))
1484 return die_c_("reading chain", chain.status());
1486 printf("[S]VP\ttest initial metadata\n");
1488 if(!compare_chain_(chain, 0, 0))
1490 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1493 printf("switch file to read-write\n");
1495 if(!change_stats_(flacfile_, /*read-only=*/false))
1498 printf("create iterator\n");
1500 FLAC::Metadata::Iterator iterator;
1501 if(!iterator.is_valid())
1502 return die_("allocating memory for iterator");
1504 our_current_position = 0;
1506 iterator.init(chain);
1508 if(0 == (block = iterator.get_block()))
1509 return die_("getting block from iterator");
1511 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1513 printf("[S]VP\tmodify STREAMINFO, write\n");
1515 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1516 FLAC__ASSERT(0 != streaminfo);
1517 streaminfo->set_sample_rate(32000);
1518 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1519 return die_("copying object");
1522 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1523 return die_c_("during chain.write(false, true)", chain.status());
1524 block = iterator.get_block();
1525 if(!compare_chain_(chain, our_current_position, block))
1528 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1531 printf("[S]VP\tnext\n");
1532 if(!iterator.next())
1533 return die_("iterator ended early\n");
1534 our_current_position++;
1536 printf("S[V]P\tnext\n");
1537 if(!iterator.next())
1538 return die_("iterator ended early\n");
1539 our_current_position++;
1541 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1542 if(0 == (block = iterator.get_block()))
1543 return die_("getting block from iterator");
1544 if(0 == (app = new FLAC::Metadata::Application()))
1545 return die_("new FLAC::Metadata::Application()");
1546 app->set_id((const unsigned char *)"duh");
1547 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1548 return die_("setting APPLICATION data");
1550 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1551 return die_("copying object");
1552 if(!iterator.set_block(app))
1553 return die_c_("iterator.set_block(app)", chain.status());
1555 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1556 return die_c_("during chain.write(false, false)", chain.status());
1557 block = iterator.get_block();
1558 if(!compare_chain_(chain, our_current_position, block))
1561 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1564 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1565 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1566 return die_("copying object");
1567 if(!app->set_data(data, 26, true))
1568 return die_("setting APPLICATION data");
1569 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1570 return die_("copying object");
1571 if(!iterator.set_block(app))
1572 return die_c_("iterator.set_block(app)", chain.status());
1574 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1575 return die_c_("during chain.write(false, false)", chain.status());
1576 block = iterator.get_block();
1577 if(!compare_chain_(chain, our_current_position, block))
1580 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1583 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1584 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1585 return die_("copying object");
1586 if(!app->set_data(data, 28, true))
1587 return die_("setting APPLICATION data");
1588 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1589 return die_("copying object");
1590 if(!iterator.set_block(app))
1591 return die_c_("iterator.set_block(app)", chain.status());
1593 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1594 return die_c_("during chain.write(false, false)", chain.status());
1595 block = iterator.get_block();
1596 if(!compare_chain_(chain, our_current_position, block))
1599 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1602 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1603 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1604 return die_("copying object");
1605 if(!app->set_data(data, 36, true))
1606 return die_("setting APPLICATION data");
1607 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1608 return die_("copying object");
1609 if(!iterator.set_block(app))
1610 return die_c_("iterator.set_block(app)", chain.status());
1612 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1613 return die_c_("during chain.write(false, false)", chain.status());
1614 block = iterator.get_block();
1615 if(!compare_chain_(chain, our_current_position, block))
1618 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1621 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1622 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1623 return die_("copying object");
1624 if(!app->set_data(data, 33, true))
1625 return die_("setting APPLICATION data");
1626 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1627 return die_("copying object");
1628 if(!iterator.set_block(app))
1629 return die_c_("iterator.set_block(app)", chain.status());
1631 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1632 return die_c_("during chain.write(true, false)", chain.status());
1633 block = iterator.get_block();
1634 if(!compare_chain_(chain, our_current_position, block))
1637 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1640 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1641 if(0 == (padding = new FLAC::Metadata::Padding()))
1642 return die_("creating PADDING block");
1643 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1644 return die_("copying object");
1645 if(!app->set_data(data, 29, true))
1646 return die_("setting APPLICATION data");
1647 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1648 return die_("copying object");
1649 padding->set_length(0);
1650 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1651 return die_("internal error");
1652 if(!iterator.set_block(app))
1653 return die_c_("iterator.set_block(app)", chain.status());
1655 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1656 return die_c_("during chain.write(true, false)", chain.status());
1657 block = iterator.get_block();
1658 if(!compare_chain_(chain, our_current_position, block))
1661 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1664 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1665 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1666 return die_("copying object");
1667 if(!app->set_data(data, 16, true))
1668 return die_("setting APPLICATION data");
1669 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1670 return die_("copying object");
1671 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1672 if(!iterator.set_block(app))
1673 return die_c_("iterator.set_block(app)", chain.status());
1675 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1676 return die_c_("during chain.write(true, false)", chain.status());
1677 block = iterator.get_block();
1678 if(!compare_chain_(chain, our_current_position, block))
1681 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1684 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1685 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1686 return die_("copying object");
1687 if(!app->set_data(data, 50, true))
1688 return die_("setting APPLICATION data");
1689 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1690 return die_("copying object");
1691 if(!iterator.set_block(app))
1692 return die_c_("iterator.set_block(app)", chain.status());
1694 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1695 return die_c_("during chain.write(true, false)", chain.status());
1696 block = iterator.get_block();
1697 if(!compare_chain_(chain, our_current_position, block))
1700 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1703 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1704 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1705 return die_("copying object");
1706 if(!app->set_data(data, 56, true))
1707 return die_("setting APPLICATION data");
1708 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1709 return die_("copying object");
1710 add_to_padding_length_(our_current_position+1, -(56 - 50));
1711 if(!iterator.set_block(app))
1712 return die_c_("iterator.set_block(app)", chain.status());
1714 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1715 return die_c_("during chain.write(true, false)", chain.status());
1716 block = iterator.get_block();
1717 if(!compare_chain_(chain, our_current_position, block))
1720 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1723 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1724 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1725 return die_("copying object");
1726 if(!app->set_data(data, 67, true))
1727 return die_("setting APPLICATION data");
1728 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1729 return die_("copying object");
1730 delete_from_our_metadata_(our_current_position+1);
1731 if(!iterator.set_block(app))
1732 return die_c_("iterator.set_block(app)", chain.status());
1734 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1735 return die_c_("during chain.write(true, false)", chain.status());
1736 block = iterator.get_block();
1737 if(!compare_chain_(chain, our_current_position, block))
1740 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1743 printf("SV[A]\tprev\n");
1744 if(!iterator.prev())
1745 return die_("iterator ended early\n");
1746 our_current_position--;
1748 printf("S[V]A\tprev\n");
1749 if(!iterator.prev())
1750 return die_("iterator ended early\n");
1751 our_current_position--;
1753 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1754 if(0 == (padding = new FLAC::Metadata::Padding()))
1755 return die_("creating PADDING block");
1756 padding->set_length(30);
1757 if(!iterator.insert_block_before(padding))
1758 printf("\titerator.insert_block_before() returned false like it should\n");
1760 return die_("iterator.insert_block_before() should have returned false");
1762 printf("[S]VA\tnext\n");
1763 if(!iterator.next())
1764 return die_("iterator ended early\n");
1765 our_current_position++;
1767 printf("S[V]A\tinsert PADDING after\n");
1768 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1769 return die_("copying metadata");
1770 if(!iterator.insert_block_after(padding))
1771 return die_("iterator.insert_block_after(padding)");
1773 block = iterator.get_block();
1774 if(!compare_chain_(chain, our_current_position, block))
1778 printf("SV[P]A\tinsert PADDING before\n");
1779 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1780 return die_("creating PADDING block");
1781 padding->set_length(17);
1782 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1783 return die_("copying metadata");
1784 if(!iterator.insert_block_before(padding))
1785 return die_("iterator.insert_block_before(padding)");
1787 block = iterator.get_block();
1788 if(!compare_chain_(chain, our_current_position, block))
1792 printf("SV[P]PA\tinsert PADDING before\n");
1793 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1794 return die_("creating PADDING block");
1795 padding->set_length(0);
1796 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1797 return die_("copying metadata");
1798 if(!iterator.insert_block_before(padding))
1799 return die_("iterator.insert_block_before(padding)");
1801 block = iterator.get_block();
1802 if(!compare_chain_(chain, our_current_position, block))
1806 printf("SV[P]PPA\tnext\n");
1807 if(!iterator.next())
1808 return die_("iterator ended early\n");
1809 our_current_position++;
1811 printf("SVP[P]PA\tnext\n");
1812 if(!iterator.next())
1813 return die_("iterator ended early\n");
1814 our_current_position++;
1816 printf("SVPP[P]A\tnext\n");
1817 if(!iterator.next())
1818 return die_("iterator ended early\n");
1819 our_current_position++;
1821 printf("SVPPP[A]\tinsert PADDING after\n");
1822 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1823 return die_("creating PADDING block");
1824 padding->set_length(57);
1825 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1826 return die_("copying metadata");
1827 if(!iterator.insert_block_after(padding))
1828 return die_("iterator.insert_block_after(padding)");
1830 block = iterator.get_block();
1831 if(!compare_chain_(chain, our_current_position, block))
1835 printf("SVPPPA[P]\tinsert PADDING before\n");
1836 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1837 return die_("creating PADDING block");
1838 padding->set_length(99);
1839 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1840 return die_("copying metadata");
1841 if(!iterator.insert_block_before(padding))
1842 return die_("iterator.insert_block_before(padding)");
1844 block = iterator.get_block();
1845 if(!compare_chain_(chain, our_current_position, block))
1850 our_current_position = 0;
1852 printf("SVPPPAPP\tmerge padding\n");
1853 chain.merge_padding();
1854 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1855 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1856 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1857 delete_from_our_metadata_(7);
1858 delete_from_our_metadata_(4);
1859 delete_from_our_metadata_(3);
1861 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1862 return die_c_("during chain.write(true, false)", chain.status());
1863 if(!compare_chain_(chain, 0, 0))
1865 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1868 printf("SVPAP\tsort padding\n");
1869 chain.sort_padding();
1870 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1871 delete_from_our_metadata_(2);
1873 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1874 return die_c_("during chain.write(true, false)", chain.status());
1875 if(!compare_chain_(chain, 0, 0))
1877 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1880 printf("create iterator\n");
1882 FLAC::Metadata::Iterator iterator;
1883 if(!iterator.is_valid())
1884 return die_("allocating memory for iterator");
1886 our_current_position = 0;
1888 iterator.init(chain);
1890 printf("[S]VAP\tnext\n");
1891 if(!iterator.next())
1892 return die_("iterator ended early\n");
1893 our_current_position++;
1895 printf("S[V]AP\tnext\n");
1896 if(!iterator.next())
1897 return die_("iterator ended early\n");
1898 our_current_position++;
1900 printf("SV[A]P\tdelete middle block, replace with padding\n");
1901 if(0 == (padding = new FLAC::Metadata::Padding()))
1902 return die_("creating PADDING block");
1903 padding->set_length(71);
1904 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1905 return die_("copying object");
1906 if(!iterator.delete_block(/*replace_with_padding=*/true))
1907 return die_c_("iterator.delete_block(true)", chain.status());
1909 block = iterator.get_block();
1910 if(!compare_chain_(chain, our_current_position, block))
1914 printf("S[V]PP\tnext\n");
1915 if(!iterator.next())
1916 return die_("iterator ended early\n");
1917 our_current_position++;
1919 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1920 delete_from_our_metadata_(our_current_position--);
1921 if(!iterator.delete_block(/*replace_with_padding=*/false))
1922 return die_c_("iterator.delete_block(false)", chain.status());
1924 block = iterator.get_block();
1925 if(!compare_chain_(chain, our_current_position, block))
1929 printf("S[V]P\tnext\n");
1930 if(!iterator.next())
1931 return die_("iterator ended early\n");
1932 our_current_position++;
1934 printf("SV[P]\tdelete last block, replace with padding\n");
1935 if(0 == (padding = new FLAC::Metadata::Padding()))
1936 return die_("creating PADDING block");
1937 padding->set_length(219);
1938 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1939 return die_("copying object");
1940 if(!iterator.delete_block(/*replace_with_padding=*/true))
1941 return die_c_("iterator.delete_block(true)", chain.status());
1943 block = iterator.get_block();
1944 if(!compare_chain_(chain, our_current_position, block))
1948 printf("S[V]P\tnext\n");
1949 if(!iterator.next())
1950 return die_("iterator ended early\n");
1951 our_current_position++;
1953 printf("SV[P]\tdelete last block, don't replace with padding\n");
1954 delete_from_our_metadata_(our_current_position--);
1955 if(!iterator.delete_block(/*replace_with_padding=*/false))
1956 return die_c_("iterator.delete_block(false)", chain.status());
1958 block = iterator.get_block();
1959 if(!compare_chain_(chain, our_current_position, block))
1963 printf("S[V]\tprev\n");
1964 if(!iterator.prev())
1965 return die_("iterator ended early\n");
1966 our_current_position--;
1968 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1969 if(iterator.delete_block(/*replace_with_padding=*/false))
1970 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1972 block = iterator.get_block();
1973 if(!compare_chain_(chain, our_current_position, block))
1977 } // delete iterator
1978 our_current_position = 0;
1980 printf("SV\tmerge padding\n");
1981 chain.merge_padding();
1983 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1984 return die_c_("during chain.write(false, false)", chain.status());
1985 if(!compare_chain_(chain, 0, 0))
1987 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1990 printf("SV\tsort padding\n");
1991 chain.sort_padding();
1993 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1994 return die_c_("during chain.write(false, false)", chain.status());
1995 if(!compare_chain_(chain, 0, 0))
1997 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
2000 if(!remove_file_(flacfile_))
2006 static bool test_level_2_misc_()
2008 ::FLAC__IOCallbacks callbacks;
2010 memset(&callbacks, 0, sizeof(callbacks));
2011 callbacks.read = (::FLAC__IOCallback_Read)fread;
2012 #ifdef FLAC__VALGRIND_TESTING
2013 callbacks.write = chain_write_cb_;
2015 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2017 callbacks.seek = chain_seek_cb_;
2018 callbacks.tell = chain_tell_cb_;
2019 callbacks.eof = chain_eof_cb_;
2021 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2023 printf("generate file\n");
2025 if(!generate_file_(/*include_extras=*/false))
2028 printf("create chain\n");
2029 FLAC::Metadata::Chain chain;
2030 if(!chain.is_valid())
2031 return die_("allocating chain");
2033 printf("read chain (filename-based)\n");
2035 if(!chain.read(flacfile_))
2036 return die_c_("reading chain", chain.status());
2038 printf("write chain with wrong method Chain::write(with callbacks)\n");
2040 if(chain.write(/*use_padding=*/false, 0, callbacks))
2041 return die_c_("mismatched write should have failed", chain.status());
2042 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2043 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2044 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2047 printf("read chain (filename-based)\n");
2049 if(!chain.read(flacfile_))
2050 return die_c_("reading chain", chain.status());
2052 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2054 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2055 return die_c_("mismatched write should have failed", chain.status());
2056 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2057 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2058 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2061 printf("read chain (callback-based)\n");
2063 FILE *file = fopen(flacfile_, "rb");
2065 return die_("opening file");
2066 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2068 return die_c_("reading chain", chain.status());
2073 printf("write chain with wrong method write()\n");
2075 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2076 return die_c_("mismatched write should have failed", chain.status());
2077 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2078 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2079 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2082 printf("read chain (callback-based)\n");
2084 FILE *file = fopen(flacfile_, "rb");
2086 return die_("opening file");
2087 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2089 return die_c_("reading chain", chain.status());
2094 printf("testing Chain::check_if_tempfile_needed()... ");
2096 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2097 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2099 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2101 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2103 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2104 return die_c_("mismatched write should have failed", chain.status());
2105 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2106 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2107 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2110 printf("read chain (callback-based)\n");
2112 FILE *file = fopen(flacfile_, "rb");
2114 return die_("opening file");
2115 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2117 return die_c_("reading chain", chain.status());
2122 printf("create iterator\n");
2124 FLAC::Metadata::Iterator iterator;
2125 if(!iterator.is_valid())
2126 return die_("allocating memory for iterator");
2128 iterator.init(chain);
2130 printf("[S]VP\tnext\n");
2131 if(!iterator.next())
2132 return die_("iterator ended early\n");
2134 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2135 if(!iterator.delete_block(/*replace_with_padding=*/false))
2136 return die_c_("block delete failed\n", chain.status());
2138 printf("testing Chain::check_if_tempfile_needed()... ");
2140 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2141 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2143 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2145 printf("write chain with wrong method Chain::write(with callbacks)\n");
2147 if(chain.write(/*use_padding=*/false, 0, callbacks))
2148 return die_c_("mismatched write should have failed", chain.status());
2149 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2150 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2151 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2154 } // delete iterator
2156 if(!remove_file_(flacfile_))
2162 bool test_metadata_file_manipulation()
2164 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2166 our_metadata_.num_blocks = 0;
2168 if(!test_level_0_())
2171 if(!test_level_1_())
2174 if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2176 if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2178 if(!test_level_2_misc_())