1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 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 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
27 #include <utime.h> /* for utime() */
28 #include <unistd.h> /* for chown(), unlink() */
29 #include <sys/stat.h> /* for stat(), maybe chmod() */
30 #include "FLAC/assert.h"
31 #include "FLAC++/decoder.h"
32 #include "FLAC++/metadata.h"
33 #include "share/grabbag.h"
34 #include "share/compat.h"
36 #include "test_libs_common/file_utils_flac.h"
39 /******************************************************************************
40 The general strategy of these tests (for interface levels 1 and 2) is
41 to create a dummy FLAC file with a known set of initial metadata
42 blocks, then keep a mirror locally of what we expect the metadata to be
43 after each operation. Then testing becomes a simple matter of running
44 a FLAC::Decoder::File over the dummy file after each operation, comparing
45 the decoded metadata to what's in our local copy. If there are any
46 differences in the metadata, or the actual audio data is corrupted, we
47 will catch it while decoding.
48 ******************************************************************************/
50 class OurFileDecoder: public FLAC::Decoder::File {
52 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
54 bool ignore_metadata_;
57 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
58 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
59 void error_callback(::FLAC__StreamDecoderErrorStatus status);
63 FLAC::Metadata::Prototype *blocks[64];
67 /* our copy of the metadata in flacfilename() */
68 static OurMetadata our_metadata_;
70 /* the current block number that corresponds to the position of the iterator we are testing */
71 static unsigned mc_our_block_number_ = 0;
73 static const char *flacfilename(bool is_ogg)
75 return is_ogg? "metadata.oga" : "metadata.flac";
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, bool is_ogg)
367 return chain.read(filename, is_ogg);
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, is_ogg);
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_(bool include_extras, bool is_ogg)
489 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
490 ::FLAC__StreamMetadata *metadata[4];
491 unsigned i = 0, n = 0;
493 printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
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_COLORS_LEN +
549 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
552 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
553 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
554 picture.length += strlen(picture.data.picture.mime_type);
555 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
556 picture.length += strlen((const char *)picture.data.picture.description);
557 picture.data.picture.width = 300;
558 picture.data.picture.height = 300;
559 picture.data.picture.depth = 24;
560 picture.data.picture.colors = 0;
561 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
562 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
563 picture.length += picture.data.picture.data_length;
566 padding.is_last = true;
567 padding.type = ::FLAC__METADATA_TYPE_PADDING;
568 padding.length = 1234;
570 metadata[n++] = &vorbiscomment;
572 metadata[n++] = cuesheet;
573 metadata[n++] = &picture;
575 metadata[n++] = &padding;
577 FLAC::Metadata::StreamInfo s(&streaminfo);
578 FLAC::Metadata::VorbisComment v(&vorbiscomment);
579 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
580 FLAC::Metadata::Picture pi(&picture);
581 FLAC::Metadata::Padding p(&padding);
583 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
584 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
585 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
586 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
587 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
589 return die_("priming our metadata");
591 if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
592 return die_("creating the encoded file");
594 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
595 free(picture.data.picture.mime_type);
596 free(picture.data.picture.description);
597 free(picture.data.picture.data);
602 static bool test_file_(bool is_ogg, bool ignore_metadata)
604 const char *filename = flacfilename(is_ogg);
605 OurFileDecoder decoder(ignore_metadata);
607 mc_our_block_number_ = 0;
608 decoder.error_occurred_ = false;
610 printf("\ttesting '%s'... ", filename);
613 if(!decoder.is_valid())
614 return die_("couldn't allocate decoder instance");
616 decoder.set_md5_checking(true);
617 decoder.set_metadata_respond_all();
618 if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
619 (void)decoder.finish();
620 return die_("initializing decoder\n");
622 if(!decoder.process_until_end_of_stream()) {
623 (void)decoder.finish();
624 return die_("decoding file\n");
627 (void)decoder.finish();
629 if(decoder.error_occurred_)
632 if(mc_our_block_number_ != our_metadata_.num_blocks)
633 return die_("short metadata block count");
639 static bool change_stats_(const char *filename, bool read_only)
641 if(!grabbag__file_change_stats(filename, read_only))
642 return die_("during grabbag__file_change_stats()");
647 static bool remove_file_(const char *filename)
649 while(our_metadata_.num_blocks > 0)
650 delete_from_our_metadata_(0);
652 if(!grabbag__file_remove_file(filename))
653 return die_("removing file");
658 static bool test_level_0_()
660 FLAC::Metadata::StreamInfo streaminfo;
662 printf("\n\n++++++ testing level 0 interface\n");
664 if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
667 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
670 printf("testing FLAC::Metadata::get_streaminfo()... ");
672 if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
673 return die_("during FLAC::Metadata::get_streaminfo()");
675 /* check to see if some basic data matches (c.f. generate_file_()) */
676 if(streaminfo.get_channels() != 1)
677 return die_("mismatch in streaminfo.get_channels()");
678 if(streaminfo.get_bits_per_sample() != 8)
679 return die_("mismatch in streaminfo.get_bits_per_sample()");
680 if(streaminfo.get_sample_rate() != 44100)
681 return die_("mismatch in streaminfo.get_sample_rate()");
682 if(streaminfo.get_min_blocksize() != 576)
683 return die_("mismatch in streaminfo.get_min_blocksize()");
684 if(streaminfo.get_max_blocksize() != 576)
685 return die_("mismatch in streaminfo.get_max_blocksize()");
690 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
692 FLAC::Metadata::VorbisComment *tags = 0;
694 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
695 return die_("during FLAC::Metadata::get_tags()");
697 /* check to see if some basic data matches (c.f. generate_file_()) */
698 if(tags->get_num_comments() != 0)
699 return die_("mismatch in tags->get_num_comments()");
707 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
709 FLAC::Metadata::VorbisComment tags;
711 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
712 return die_("during FLAC::Metadata::get_tags()");
714 /* check to see if some basic data matches (c.f. generate_file_()) */
715 if(tags.get_num_comments() != 0)
716 return die_("mismatch in tags.get_num_comments()");
722 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
724 FLAC::Metadata::CueSheet *cuesheet = 0;
726 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
727 return die_("during FLAC::Metadata::get_cuesheet()");
729 /* check to see if some basic data matches (c.f. generate_file_()) */
730 if(cuesheet->get_lead_in() != 123)
731 return die_("mismatch in cuesheet->get_lead_in()");
739 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
741 FLAC::Metadata::CueSheet cuesheet;
743 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
744 return die_("during FLAC::Metadata::get_cuesheet()");
746 /* check to see if some basic data matches (c.f. generate_file_()) */
747 if(cuesheet.get_lead_in() != 123)
748 return die_("mismatch in cuesheet.get_lead_in()");
754 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
756 FLAC::Metadata::Picture *picture = 0;
758 if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), 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)))
759 return die_("during FLAC::Metadata::get_picture()");
761 /* check to see if some basic data matches (c.f. generate_file_()) */
762 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
763 return die_("mismatch in picture->get_type ()");
771 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
773 FLAC::Metadata::Picture picture;
775 if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), 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)))
776 return die_("during FLAC::Metadata::get_picture()");
778 /* check to see if some basic data matches (c.f. generate_file_()) */
779 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
780 return die_("mismatch in picture->get_type ()");
785 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
791 static bool test_level_1_()
793 FLAC::Metadata::Prototype *block;
794 FLAC::Metadata::StreamInfo *streaminfo;
795 FLAC::Metadata::Padding *padding;
796 FLAC::Metadata::Application *app;
797 FLAC__byte data[1000];
798 unsigned our_current_position = 0;
800 // initialize 'data' to avoid Valgrind errors
801 memset(data, 0, sizeof(data));
803 printf("\n\n++++++ testing level 1 interface\n");
805 /************************************************************/
807 printf("simple iterator on read-only file\n");
809 if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
812 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
815 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
818 FLAC::Metadata::SimpleIterator iterator;
820 if(!iterator.is_valid())
821 return die_("iterator.is_valid() returned false");
823 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
824 return die_("iterator.init() returned false");
826 printf("is writable = %u\n", (unsigned)iterator.is_writable());
827 if(iterator.is_writable())
828 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
830 printf("iterate forwards\n");
832 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
833 return die_("expected STREAMINFO type from iterator.get_block_type()");
834 if(0 == (block = iterator.get_block()))
835 return die_("getting block 0");
836 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
837 return die_("expected STREAMINFO type");
838 if(block->get_is_last())
839 return die_("expected is_last to be false");
840 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
841 return die_("bad STREAMINFO length");
842 /* check to see if some basic data matches (c.f. generate_file_()) */
843 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
844 FLAC__ASSERT(0 != streaminfo);
845 if(streaminfo->get_channels() != 1)
846 return die_("mismatch in channels");
847 if(streaminfo->get_bits_per_sample() != 8)
848 return die_("mismatch in bits_per_sample");
849 if(streaminfo->get_sample_rate() != 44100)
850 return die_("mismatch in sample_rate");
851 if(streaminfo->get_min_blocksize() != 576)
852 return die_("mismatch in min_blocksize");
853 if(streaminfo->get_max_blocksize() != 576)
854 return die_("mismatch in max_blocksize");
855 // we will delete streaminfo a little later when we're really done with it...
858 return die_("forward iterator ended early");
859 our_current_position++;
862 return die_("forward iterator ended early");
863 our_current_position++;
865 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
866 return die_("expected PADDING type from iterator.get_block_type()");
867 if(0 == (block = iterator.get_block()))
868 return die_("getting block 1");
869 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
870 return die_("expected PADDING type");
871 if(!block->get_is_last())
872 return die_("expected is_last to be true");
873 /* check to see if some basic data matches (c.f. generate_file_()) */
874 if(block->get_length() != 1234)
875 return die_("bad PADDING length");
879 return die_("forward iterator returned true but should have returned false");
881 printf("iterate backwards\n");
883 return die_("reverse iterator ended early");
885 return die_("reverse iterator ended early");
887 return die_("reverse iterator returned true but should have returned false");
889 printf("testing iterator.set_block() on read-only file...\n");
891 if(!iterator.set_block(streaminfo, false))
892 printf("PASSED. iterator.set_block() returned false like it should\n");
894 return die_("iterator.set_block() returned true but shouldn't have");
898 /************************************************************/
900 printf("simple iterator on writable file\n");
902 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
905 printf("creating APPLICATION block\n");
907 if(0 == (app = new FLAC::Metadata::Application()))
908 return die_("new FLAC::Metadata::Application()");
909 app->set_id((const unsigned char *)"duh");
911 printf("creating PADDING block\n");
913 if(0 == (padding = new FLAC::Metadata::Padding()))
914 return die_("new FLAC::Metadata::Padding()");
915 padding->set_length(20);
917 FLAC::Metadata::SimpleIterator iterator;
919 if(!iterator.is_valid())
920 return die_("iterator.is_valid() returned false");
922 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
923 return die_("iterator.init() returned false");
924 our_current_position = 0;
926 printf("is writable = %u\n", (unsigned)iterator.is_writable());
928 printf("[S]VP\ttry to write over STREAMINFO block...\n");
929 if(!iterator.set_block(app, false))
930 printf("\titerator.set_block() returned false like it should\n");
932 return die_("iterator.set_block() returned true but shouldn't have");
934 printf("[S]VP\tnext\n");
936 return die_("iterator ended early\n");
937 our_current_position++;
939 printf("S[V]P\tnext\n");
941 return die_("iterator ended early\n");
942 our_current_position++;
944 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
945 padding->set_length(25);
946 if(!iterator.insert_block_after(padding, false))
947 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
948 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
951 printf("SVP[P]\tprev\n");
953 return die_("iterator ended early\n");
954 our_current_position--;
956 printf("SV[P]P\tprev\n");
958 return die_("iterator ended early\n");
959 our_current_position--;
961 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
962 padding->set_length(30);
963 if(!iterator.insert_block_after(padding, false))
964 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
965 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
968 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
971 printf("SV[P]PP\tprev\n");
973 return die_("iterator ended early\n");
974 our_current_position--;
976 printf("S[V]PPP\tprev\n");
978 return die_("iterator ended early\n");
979 our_current_position--;
981 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
982 if(iterator.delete_block(false))
983 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
985 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
988 printf("[S]VPPP\tnext\n");
990 return die_("iterator ended early\n");
991 our_current_position++;
993 printf("S[V]PPP\tnext\n");
995 return die_("iterator ended early\n");
996 our_current_position++;
998 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
999 if(!iterator.delete_block(true))
1000 return die_ss_("iterator.delete_block(true)", iterator);
1001 our_current_position--;
1003 printf("S[V]PPP\tnext\n");
1004 if(!iterator.next())
1005 return die_("iterator ended early\n");
1006 our_current_position++;
1008 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1009 if(!iterator.delete_block(false))
1010 return die_ss_("iterator.delete_block(false)", iterator);
1011 delete_from_our_metadata_(our_current_position--);
1013 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1016 printf("S[V]PP\tnext\n");
1017 if(!iterator.next())
1018 return die_("iterator ended early\n");
1019 our_current_position++;
1021 printf("SV[P]P\tnext\n");
1022 if(!iterator.next())
1023 return die_("iterator ended early\n");
1024 our_current_position++;
1026 printf("SVP[P]\tdelete (last block), replace with padding\n");
1027 if(!iterator.delete_block(true))
1028 return die_ss_("iterator.delete_block(false)", iterator);
1029 our_current_position--;
1031 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1034 printf("SV[P]P\tnext\n");
1035 if(!iterator.next())
1036 return die_("iterator ended early\n");
1037 our_current_position++;
1039 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1040 if(!iterator.delete_block(false))
1041 return die_ss_("iterator.delete_block(false)", iterator);
1042 delete_from_our_metadata_(our_current_position--);
1044 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1047 printf("SV[P]\tprev\n");
1048 if(!iterator.prev())
1049 return die_("iterator ended early\n");
1050 our_current_position--;
1052 printf("S[V]P\tprev\n");
1053 if(!iterator.prev())
1054 return die_("iterator ended early\n");
1055 our_current_position--;
1057 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1058 FLAC__ASSERT(our_current_position == 0);
1059 block = iterator.get_block();
1060 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1061 FLAC__ASSERT(0 != streaminfo);
1062 streaminfo->set_sample_rate(32000);
1063 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1064 return die_("copying object");
1065 if(!iterator.set_block(block, false))
1066 return die_ss_("iterator.set_block(block, false)", iterator);
1069 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1072 printf("[S]VP\tnext\n");
1073 if(!iterator.next())
1074 return die_("iterator ended early\n");
1075 our_current_position++;
1077 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1078 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1079 if(!iterator.insert_block_after(app, true))
1080 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1081 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1083 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1085 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1088 printf("SV[A]P\tnext\n");
1089 if(!iterator.next())
1090 return die_("iterator ended early\n");
1091 our_current_position++;
1093 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1094 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1095 if(!iterator.set_block(app, true))
1096 return die_ss_("iterator.set_block(app, true)", iterator);
1097 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1099 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1101 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1104 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1105 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1106 if(!app->set_data(data, sizeof(data), true))
1107 return die_("setting APPLICATION data");
1108 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1109 return die_("copying object");
1110 if(!iterator.set_block(app, false))
1111 return die_ss_("iterator.set_block(app, false)", iterator);
1113 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1116 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1117 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1118 if(!app->set_data(data, 12, true))
1119 return die_("setting APPLICATION data");
1120 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1121 return die_("copying object");
1122 if(!iterator.set_block(app, false))
1123 return die_ss_("iterator.set_block(app, false)", iterator);
1125 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1128 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1129 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1130 if(!app->set_data(data, sizeof(data), true))
1131 return die_("setting APPLICATION data");
1132 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1133 return die_("copying object");
1134 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1135 if(!iterator.set_block(app, true))
1136 return die_ss_("iterator.set_block(app, true)", iterator);
1138 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1141 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1142 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1143 if(!app->set_data(data, 23, true))
1144 return die_("setting APPLICATION data");
1145 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1146 return die_("copying object");
1147 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1148 return die_("copying object");
1149 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1150 if(!iterator.set_block(app, true))
1151 return die_ss_("iterator.set_block(app, true)", iterator);
1153 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1156 printf("SVA[A]PP\tnext\n");
1157 if(!iterator.next())
1158 return die_("iterator ended early\n");
1159 our_current_position++;
1161 printf("SVAA[P]P\tnext\n");
1162 if(!iterator.next())
1163 return die_("iterator ended early\n");
1164 our_current_position++;
1166 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1167 padding->set_length(5);
1168 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1169 return die_("copying object");
1170 if(!iterator.set_block(padding, false))
1171 return die_ss_("iterator.set_block(padding, false)", iterator);
1173 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1176 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1177 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1178 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1179 return die_("copying object");
1180 if(!iterator.set_block(app, false))
1181 return die_ss_("iterator.set_block(app, false)", iterator);
1183 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1186 printf("SVAAP[A]\tset PADDING (equal)\n");
1187 padding->set_length(27);
1188 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1189 return die_("copying object");
1190 if(!iterator.set_block(padding, false))
1191 return die_ss_("iterator.set_block(padding, false)", iterator);
1193 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1196 printf("SVAAP[P]\tprev\n");
1197 if(!iterator.prev())
1198 return die_("iterator ended early\n");
1199 our_current_position--;
1201 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1202 if(!iterator.delete_block(false))
1203 return die_ss_("iterator.delete_block(false)", iterator);
1204 delete_from_our_metadata_(our_current_position--);
1206 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1209 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1210 if(!iterator.delete_block(false))
1211 return die_ss_("iterator.delete_block(false)", iterator);
1212 delete_from_our_metadata_(our_current_position--);
1214 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1217 printf("SV[A]P\tnext\n");
1218 if(!iterator.next())
1219 return die_("iterator ended early\n");
1220 our_current_position++;
1222 printf("SVA[P]\tinsert PADDING after\n");
1223 padding->set_length(5);
1224 if(!iterator.insert_block_after(padding, false))
1225 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1226 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1229 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1232 printf("SVAP[P]\tprev\n");
1233 if(!iterator.prev())
1234 return die_("iterator ended early\n");
1235 our_current_position--;
1237 printf("SVA[P]P\tprev\n");
1238 if(!iterator.prev())
1239 return die_("iterator ended early\n");
1240 our_current_position--;
1242 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1243 if(!app->set_data(data, 32, true))
1244 return die_("setting APPLICATION data");
1245 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1246 return die_("copying object");
1247 if(!iterator.set_block(app, true))
1248 return die_ss_("iterator.set_block(app, true)", iterator);
1250 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1253 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1254 if(!app->set_data(data, 60, true))
1255 return die_("setting APPLICATION data");
1256 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1257 return die_("copying object");
1258 if(!iterator.set_block(app, true))
1259 return die_ss_("iterator.set_block(app, true)", iterator);
1261 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1264 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1265 if(!app->set_data(data, 87, true))
1266 return die_("setting APPLICATION data");
1267 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1268 return die_("copying object");
1269 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1270 if(!iterator.set_block(app, true))
1271 return die_ss_("iterator.set_block(app, true)", iterator);
1273 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1276 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1277 if(!app->set_data(data, 91, true))
1278 return die_("setting APPLICATION data");
1279 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1280 return die_("copying object");
1281 delete_from_our_metadata_(our_current_position+1);
1282 if(!iterator.set_block(app, true))
1283 return die_ss_("iterator.set_block(app, true)", iterator);
1285 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1288 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1289 if(!app->set_data(data, 100, true))
1290 return die_("setting APPLICATION data");
1291 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1292 return die_("copying object");
1293 delete_from_our_metadata_(our_current_position+1);
1294 our_metadata_.blocks[our_current_position]->set_is_last(true);
1295 if(!iterator.set_block(app, true))
1296 return die_ss_("iterator.set_block(app, true)", iterator);
1298 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1301 printf("SV[A]\tset PADDING (equal size)\n");
1302 padding->set_length(app->get_length());
1303 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1304 return die_("copying object");
1305 if(!iterator.set_block(padding, true))
1306 return die_ss_("iterator.set_block(padding, true)", iterator);
1308 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1311 printf("SV[P]\tinsert PADDING after\n");
1312 if(!iterator.insert_block_after(padding, false))
1313 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1314 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1317 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1320 printf("SVP[P]\tinsert PADDING after\n");
1321 padding->set_length(5);
1322 if(!iterator.insert_block_after(padding, false))
1323 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1324 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1327 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1330 printf("SVPP[P]\tprev\n");
1331 if(!iterator.prev())
1332 return die_("iterator ended early\n");
1333 our_current_position--;
1335 printf("SVP[P]P\tprev\n");
1336 if(!iterator.prev())
1337 return die_("iterator ended early\n");
1338 our_current_position--;
1340 printf("SV[P]PP\tprev\n");
1341 if(!iterator.prev())
1342 return die_("iterator ended early\n");
1343 our_current_position--;
1345 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1346 if(!app->set_data(data, 101, true))
1347 return die_("setting APPLICATION data");
1348 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1349 return die_("copying object");
1350 if(!iterator.insert_block_after(app, true))
1351 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1353 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1356 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1357 if(!iterator.delete_block(false))
1358 return die_ss_("iterator.delete_block(false)", iterator);
1359 delete_from_our_metadata_(our_current_position--);
1361 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1364 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1365 if(!app->set_data(data, 97, true))
1366 return die_("setting APPLICATION data");
1367 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1368 return die_("copying object");
1369 if(!iterator.insert_block_after(app, true))
1370 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1372 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1375 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1376 if(!iterator.delete_block(false))
1377 return die_ss_("iterator.delete_block(false)", iterator);
1378 delete_from_our_metadata_(our_current_position--);
1380 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1383 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1384 if(!app->set_data(data, 100, true))
1385 return die_("setting APPLICATION data");
1386 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1387 return die_("copying object");
1388 delete_from_our_metadata_(our_current_position+1);
1389 if(!iterator.insert_block_after(app, true))
1390 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1392 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1395 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1396 if(!iterator.delete_block(false))
1397 return die_ss_("iterator.delete_block(false)", iterator);
1398 delete_from_our_metadata_(our_current_position--);
1400 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1403 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1404 if(!app->set_data(data, 96, true))
1405 return die_("setting APPLICATION data");
1406 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1407 return die_("copying object");
1408 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1409 if(!iterator.insert_block_after(app, true))
1410 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1412 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1415 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1416 if(!iterator.delete_block(false))
1417 return die_ss_("iterator.delete_block(false)", iterator);
1418 delete_from_our_metadata_(our_current_position--);
1420 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1423 printf("S[V]PP\tnext\n");
1424 if(!iterator.next())
1425 return die_("iterator ended early\n");
1426 our_current_position++;
1428 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1429 if(!iterator.delete_block(false))
1430 return die_ss_("iterator.delete_block(false)", iterator);
1431 delete_from_our_metadata_(our_current_position--);
1433 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1436 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1437 if(!app->set_data(data, 1, true))
1438 return die_("setting APPLICATION data");
1439 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1440 return die_("copying object");
1441 delete_from_our_metadata_(our_current_position+1);
1442 if(!iterator.insert_block_after(app, true))
1443 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1445 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1452 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1458 static bool test_level_2_(bool filename_based, bool is_ogg)
1460 FLAC::Metadata::Prototype *block;
1461 FLAC::Metadata::StreamInfo *streaminfo;
1462 FLAC::Metadata::Application *app;
1463 FLAC::Metadata::Padding *padding;
1464 FLAC__byte data[2000];
1465 unsigned our_current_position;
1467 // initialize 'data' to avoid Valgrind errors
1468 memset(data, 0, sizeof(data));
1470 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1472 printf("generate read-only file\n");
1474 if(!generate_file_(/*include_extras=*/false, is_ogg))
1477 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1480 printf("create chain\n");
1481 FLAC::Metadata::Chain chain;
1482 if(!chain.is_valid())
1483 return die_("allocating memory for chain");
1485 printf("read chain\n");
1487 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1488 return die_c_("reading chain", chain.status());
1490 printf("[S]VP\ttest initial metadata\n");
1492 if(!compare_chain_(chain, 0, 0))
1494 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1500 printf("switch file to read-write\n");
1502 if(!change_stats_(flacfilename(is_ogg), /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
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_(is_ogg, /*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, flacfilename(is_ogg)))
1869 return die_c_("during chain.write(true, false)", chain.status());
1870 if(!compare_chain_(chain, 0, 0))
1872 if(!test_file_(is_ogg, /*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, flacfilename(is_ogg)))
1881 return die_c_("during chain.write(true, false)", chain.status());
1882 if(!compare_chain_(chain, 0, 0))
1884 if(!test_file_(is_ogg, /*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, flacfilename(is_ogg)))
1991 return die_c_("during chain.write(false, false)", chain.status());
1992 if(!compare_chain_(chain, 0, 0))
1994 if(!test_file_(is_ogg, /*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, flacfilename(is_ogg)))
2001 return die_c_("during chain.write(false, false)", chain.status());
2002 if(!compare_chain_(chain, 0, 0))
2004 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2008 if(!remove_file_(flacfilename(is_ogg)))
2014 static bool test_level_2_misc_(bool is_ogg)
2016 ::FLAC__IOCallbacks callbacks;
2018 memset(&callbacks, 0, sizeof(callbacks));
2019 callbacks.read = (::FLAC__IOCallback_Read)fread;
2020 #ifdef FLAC__VALGRIND_TESTING
2021 callbacks.write = chain_write_cb_;
2023 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2025 callbacks.seek = chain_seek_cb_;
2026 callbacks.tell = chain_tell_cb_;
2027 callbacks.eof = chain_eof_cb_;
2029 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2031 printf("generate file\n");
2033 if(!generate_file_(/*include_extras=*/false, is_ogg))
2036 printf("create chain\n");
2037 FLAC::Metadata::Chain chain;
2038 if(!chain.is_valid())
2039 return die_("allocating chain");
2041 printf("read chain (filename-based)\n");
2043 if(!chain.read(flacfilename(is_ogg)))
2044 return die_c_("reading chain", chain.status());
2046 printf("write chain with wrong method Chain::write(with callbacks)\n");
2048 if(chain.write(/*use_padding=*/false, 0, callbacks))
2049 return die_c_("mismatched write should have failed", chain.status());
2050 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2051 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2052 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2055 printf("read chain (filename-based)\n");
2057 if(!chain.read(flacfilename(is_ogg)))
2058 return die_c_("reading chain", chain.status());
2060 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2062 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2063 return die_c_("mismatched write should have failed", chain.status());
2064 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2065 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2066 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2069 printf("read chain (callback-based)\n");
2071 FILE *file = fopen(flacfilename(is_ogg), "rb");
2073 return die_("opening file");
2074 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2076 return die_c_("reading chain", chain.status());
2081 printf("write chain with wrong method write()\n");
2083 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2084 return die_c_("mismatched write should have failed", chain.status());
2085 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2086 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2087 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2090 printf("read chain (callback-based)\n");
2092 FILE *file = fopen(flacfilename(is_ogg), "rb");
2094 return die_("opening file");
2095 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2097 return die_c_("reading chain", chain.status());
2102 printf("testing Chain::check_if_tempfile_needed()... ");
2104 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2105 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2107 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2109 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2111 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2112 return die_c_("mismatched write should have failed", chain.status());
2113 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2114 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2115 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2118 printf("read chain (callback-based)\n");
2120 FILE *file = fopen(flacfilename(is_ogg), "rb");
2122 return die_("opening file");
2123 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2125 return die_c_("reading chain", chain.status());
2130 printf("create iterator\n");
2132 FLAC::Metadata::Iterator iterator;
2133 if(!iterator.is_valid())
2134 return die_("allocating memory for iterator");
2136 iterator.init(chain);
2138 printf("[S]VP\tnext\n");
2139 if(!iterator.next())
2140 return die_("iterator ended early\n");
2142 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2143 if(!iterator.delete_block(/*replace_with_padding=*/false))
2144 return die_c_("block delete failed\n", chain.status());
2146 printf("testing Chain::check_if_tempfile_needed()... ");
2148 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2149 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2151 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2153 printf("write chain with wrong method Chain::write(with callbacks)\n");
2155 if(chain.write(/*use_padding=*/false, 0, callbacks))
2156 return die_c_("mismatched write should have failed", chain.status());
2157 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2158 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2159 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2162 } // delete iterator
2164 if(!remove_file_(flacfilename(is_ogg)))
2170 bool test_metadata_file_manipulation()
2172 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2174 our_metadata_.num_blocks = 0;
2176 if(!test_level_0_())
2179 if(!test_level_1_())
2182 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2184 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2186 if(!test_level_2_misc_(/*is_ogg=*/false))
2189 if(FLAC_API_SUPPORTS_OGG_FLAC) {
2190 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2192 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2195 /* when ogg flac write is supported, will have to add this: */
2196 if(!test_level_2_misc_(/*is_ogg=*/true))