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 along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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"
35 #include "share/macros.h"
37 #include "test_libs_common/file_utils_flac.h"
40 /******************************************************************************
41 The general strategy of these tests (for interface levels 1 and 2) is
42 to create a dummy FLAC file with a known set of initial metadata
43 blocks, then keep a mirror locally of what we expect the metadata to be
44 after each operation. Then testing becomes a simple matter of running
45 a FLAC::Decoder::File over the dummy file after each operation, comparing
46 the decoded metadata to what's in our local copy. If there are any
47 differences in the metadata, or the actual audio data is corrupted, we
48 will catch it while decoding.
49 ******************************************************************************/
51 class OurFileDecoder: public FLAC::Decoder::File {
53 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
55 bool ignore_metadata_;
58 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
59 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
60 void error_callback(::FLAC__StreamDecoderErrorStatus status);
64 FLAC::Metadata::Prototype *blocks[64];
68 /* our copy of the metadata in flacfilename() */
69 static OurMetadata our_metadata_;
71 /* the current block number that corresponds to the position of the iterator we are testing */
72 static unsigned mc_our_block_number_ = 0;
74 static const char *flacfilename(bool is_ogg)
76 return is_ogg? "metadata.oga" : "metadata.flac";
79 static bool die_(const char *msg)
81 printf("ERROR: %s\n", msg);
85 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
87 printf("ERROR: %s\n", msg);
88 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
92 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
94 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
95 printf("ERROR: %s\n", msg);
96 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
100 static void *malloc_or_die_(size_t size)
102 void *x = malloc(size);
104 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
110 static char *strdup_or_die_(const char *s)
114 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
120 /* functions for working with our metadata copy */
122 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
125 FLAC::Metadata::Prototype *obj = block;
126 FLAC__ASSERT(position < our_metadata_.num_blocks);
128 if(0 == (obj = FLAC::Metadata::clone(block)))
129 return die_("during FLAC::Metadata::clone()");
131 delete our_metadata_.blocks[position];
132 our_metadata_.blocks[position] = obj;
134 /* set the is_last flags */
135 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
136 our_metadata_.blocks[i]->set_is_last(false);
137 our_metadata_.blocks[i]->set_is_last(true);
142 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
145 FLAC::Metadata::Prototype *obj = block;
147 if(0 == (obj = FLAC::Metadata::clone(block)))
148 return die_("during FLAC::Metadata::clone()");
150 if(position > our_metadata_.num_blocks) {
151 position = our_metadata_.num_blocks;
154 for(i = our_metadata_.num_blocks; i > position; i--)
155 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
157 our_metadata_.blocks[position] = obj;
158 our_metadata_.num_blocks++;
160 /* set the is_last flags */
161 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
162 our_metadata_.blocks[i]->set_is_last(false);
163 our_metadata_.blocks[i]->set_is_last(true);
168 static void delete_from_our_metadata_(unsigned position)
171 FLAC__ASSERT(position < our_metadata_.num_blocks);
172 delete our_metadata_.blocks[position];
173 for(i = position; i < our_metadata_.num_blocks - 1; i++)
174 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
175 our_metadata_.num_blocks--;
177 /* set the is_last flags */
178 if(our_metadata_.num_blocks > 0) {
179 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
180 our_metadata_.blocks[i]->set_is_last(false);
181 our_metadata_.blocks[i]->set_is_last(true);
185 void add_to_padding_length_(unsigned index, int delta)
187 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
188 FLAC__ASSERT(0 != padding);
189 padding->set_length((unsigned)((int)padding->get_length() + delta));
193 * This wad of functions supports filename- and callback-based chain reading/writing.
194 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
196 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
198 static const char *tempfile_suffix = ".metadata_edit";
200 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
202 strcpy(*tempfilename, filename);
203 strcat(*tempfilename, tempfile_suffix);
205 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
211 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
214 (void)fclose(*tempfile);
218 if(0 != *tempfilename) {
219 (void)unlink(*tempfilename);
225 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
227 FLAC__ASSERT(0 != filename);
228 FLAC__ASSERT(0 != tempfile);
229 FLAC__ASSERT(0 != tempfilename);
230 FLAC__ASSERT(0 != *tempfilename);
233 (void)fclose(*tempfile);
237 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
238 /* on some flavors of windows, rename() will fail if the destination already exists */
239 if(unlink(filename) < 0) {
240 cleanup_tempfile_(tempfile, tempfilename);
245 if(0 != rename(*tempfilename, filename)) {
246 cleanup_tempfile_(tempfile, tempfilename);
250 cleanup_tempfile_(tempfile, tempfilename);
255 bool get_file_stats_(const char *filename, struct stat *stats)
257 FLAC__ASSERT(0 != filename);
258 FLAC__ASSERT(0 != stats);
259 return (0 == stat(filename, stats));
262 void set_file_stats_(const char *filename, struct stat *stats)
264 struct utimbuf srctime;
266 FLAC__ASSERT(0 != filename);
267 FLAC__ASSERT(0 != stats);
269 srctime.actime = stats->st_atime;
270 srctime.modtime = stats->st_mtime;
271 (void)chmod(filename, stats->st_mode);
272 (void)utime(filename, &srctime);
273 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
274 FLAC_CHECK_RETURN(chown(filename, stats->st_uid, (gid_t)(-1)));
275 FLAC_CHECK_RETURN(chown(filename, (uid_t)(-1), stats->st_gid));
279 #ifdef FLAC__VALGRIND_TESTING
280 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
282 FILE *stream = (FILE*)handle;
283 size_t ret = fwrite(ptr, size, nmemb, stream);
290 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
292 off_t o = (off_t)offset;
293 FLAC__ASSERT(offset == o);
294 return fseeko((FILE*)handle, o, whence);
297 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
299 return ftello((FILE*)handle);
302 static int chain_eof_cb_(::FLAC__IOHandle handle)
304 return feof((FILE*)handle);
307 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
310 return chain.write(use_padding, preserve_file_stats);
312 ::FLAC__IOCallbacks callbacks;
314 memset(&callbacks, 0, sizeof(callbacks));
315 callbacks.read = (::FLAC__IOCallback_Read)fread;
316 #ifdef FLAC__VALGRIND_TESTING
317 callbacks.write = chain_write_cb_;
319 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
321 callbacks.seek = chain_seek_cb_;
322 callbacks.eof = chain_eof_cb_;
324 if(chain.check_if_tempfile_needed(use_padding)) {
326 FILE *file, *tempfile;
328 if(preserve_file_stats) {
329 if(!get_file_stats_(filename, &stats))
332 if(0 == (file = fopen(filename, "rb")))
333 return false; /*@@@@ chain status still says OK though */
334 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
336 cleanup_tempfile_(&tempfile, &tempfilename);
337 return false; /*@@@@ chain status still says OK though */
339 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
347 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
349 if(preserve_file_stats)
350 set_file_stats_(filename, &stats);
353 FILE *file = fopen(filename, "r+b");
355 return false; /*@@@@ chain status still says OK though */
356 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks)) {
367 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg)
370 return chain.read(filename, is_ogg);
372 ::FLAC__IOCallbacks callbacks;
374 memset(&callbacks, 0, sizeof(callbacks));
375 callbacks.read = (::FLAC__IOCallback_Read)fread;
376 callbacks.seek = chain_seek_cb_;
377 callbacks.tell = chain_tell_cb_;
381 FILE *file = fopen(filename, "rb");
383 return false; /*@@@@ chain status still says OK though */
384 ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg);
391 /* function for comparing our metadata to a FLAC::Metadata::Chain */
393 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
396 FLAC::Metadata::Iterator iterator;
399 printf("\tcomparing chain... ");
402 if(!iterator.is_valid())
403 return die_("allocating memory for iterator");
405 iterator.init(chain);
409 FLAC::Metadata::Prototype *block;
414 if(0 == (block = iterator.get_block()))
415 return die_("getting block from iterator");
417 if(*block != *our_metadata_.blocks[i])
418 return die_("metadata block mismatch");
422 next_ok = iterator.next();
423 } while(i < our_metadata_.num_blocks && next_ok);
426 return die_("chain has more blocks than expected");
428 if(i < our_metadata_.num_blocks)
429 return die_("short block count in chain");
431 if(0 != current_block) {
432 printf("CURRENT_POSITION... ");
435 if(*current_block != *our_metadata_.blocks[current_position])
436 return die_("metadata block mismatch");
444 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
449 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
450 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
452 printf("content... ");
456 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
459 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
461 /* don't bother checking if we've already hit an error */
465 printf("%d... ", mc_our_block_number_);
468 if(!ignore_metadata_) {
469 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
470 (void)die_("got more metadata blocks than expected");
471 error_occurred_ = true;
474 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
475 (void)die_("metadata block mismatch");
476 error_occurred_ = true;
481 mc_our_block_number_++;
484 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
486 error_occurred_ = true;
487 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
490 static bool generate_file_(bool include_extras, bool is_ogg)
492 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
493 ::FLAC__StreamMetadata *metadata[4];
494 unsigned i = 0, n = 0;
496 printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
498 while(our_metadata_.num_blocks > 0)
499 delete_from_our_metadata_(0);
501 streaminfo.is_last = false;
502 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
503 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
504 streaminfo.data.stream_info.min_blocksize = 576;
505 streaminfo.data.stream_info.max_blocksize = 576;
506 streaminfo.data.stream_info.min_framesize = 0;
507 streaminfo.data.stream_info.max_framesize = 0;
508 streaminfo.data.stream_info.sample_rate = 44100;
509 streaminfo.data.stream_info.channels = 1;
510 streaminfo.data.stream_info.bits_per_sample = 8;
511 streaminfo.data.stream_info.total_samples = 0;
512 memset(streaminfo.data.stream_info.md5sum, 0, 16);
515 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
516 vorbiscomment.is_last = false;
517 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
518 vorbiscomment.length = (4 + vendor_string_length) + 4;
519 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
520 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
521 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
522 vorbiscomment.data.vorbis_comment.num_comments = 0;
523 vorbiscomment.data.vorbis_comment.comments = 0;
527 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
528 return die_("priming our metadata");
529 cuesheet->is_last = false;
530 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
531 cuesheet->data.cue_sheet.lead_in = 123;
532 cuesheet->data.cue_sheet.is_cd = false;
533 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
534 return die_("priming our metadata");
535 cuesheet->data.cue_sheet.tracks[0].number = 1;
536 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
537 return die_("priming our metadata");
541 picture.is_last = false;
542 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
545 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
546 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
547 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
548 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
549 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
550 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
551 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
552 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
555 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
556 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
557 picture.length += strlen(picture.data.picture.mime_type);
558 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
559 picture.length += strlen((const char *)picture.data.picture.description);
560 picture.data.picture.width = 300;
561 picture.data.picture.height = 300;
562 picture.data.picture.depth = 24;
563 picture.data.picture.colors = 0;
564 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
565 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
566 picture.length += picture.data.picture.data_length;
569 padding.is_last = true;
570 padding.type = ::FLAC__METADATA_TYPE_PADDING;
571 padding.length = 1234;
573 metadata[n++] = &vorbiscomment;
575 metadata[n++] = cuesheet;
576 metadata[n++] = &picture;
578 metadata[n++] = &padding;
580 FLAC::Metadata::StreamInfo s(&streaminfo);
581 FLAC::Metadata::VorbisComment v(&vorbiscomment);
582 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
583 FLAC::Metadata::Picture pi(&picture);
584 FLAC::Metadata::Padding p(&padding);
586 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
587 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
588 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
589 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
590 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
592 return die_("priming our metadata");
594 if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
595 return die_("creating the encoded file");
597 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
598 free(picture.data.picture.mime_type);
599 free(picture.data.picture.description);
600 free(picture.data.picture.data);
605 static bool test_file_(bool is_ogg, bool ignore_metadata)
607 const char *filename = flacfilename(is_ogg);
608 OurFileDecoder decoder(ignore_metadata);
610 mc_our_block_number_ = 0;
611 decoder.error_occurred_ = false;
613 printf("\ttesting '%s'... ", filename);
616 if(!decoder.is_valid())
617 return die_("couldn't allocate decoder instance");
619 decoder.set_md5_checking(true);
620 decoder.set_metadata_respond_all();
621 if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
622 (void)decoder.finish();
623 return die_("initializing decoder\n");
625 if(!decoder.process_until_end_of_stream()) {
626 (void)decoder.finish();
627 return die_("decoding file\n");
630 (void)decoder.finish();
632 if(decoder.error_occurred_)
635 if(mc_our_block_number_ != our_metadata_.num_blocks)
636 return die_("short metadata block count");
642 static bool change_stats_(const char *filename, bool read_only)
644 if(!grabbag__file_change_stats(filename, read_only))
645 return die_("during grabbag__file_change_stats()");
650 static bool remove_file_(const char *filename)
652 while(our_metadata_.num_blocks > 0)
653 delete_from_our_metadata_(0);
655 if(!grabbag__file_remove_file(filename))
656 return die_("removing file");
661 static bool test_level_0_()
663 FLAC::Metadata::StreamInfo streaminfo;
665 printf("\n\n++++++ testing level 0 interface\n");
667 if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
670 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
673 printf("testing FLAC::Metadata::get_streaminfo()... ");
675 if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
676 return die_("during FLAC::Metadata::get_streaminfo()");
678 /* check to see if some basic data matches (c.f. generate_file_()) */
679 if(streaminfo.get_channels() != 1)
680 return die_("mismatch in streaminfo.get_channels()");
681 if(streaminfo.get_bits_per_sample() != 8)
682 return die_("mismatch in streaminfo.get_bits_per_sample()");
683 if(streaminfo.get_sample_rate() != 44100)
684 return die_("mismatch in streaminfo.get_sample_rate()");
685 if(streaminfo.get_min_blocksize() != 576)
686 return die_("mismatch in streaminfo.get_min_blocksize()");
687 if(streaminfo.get_max_blocksize() != 576)
688 return die_("mismatch in streaminfo.get_max_blocksize()");
693 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
695 FLAC::Metadata::VorbisComment *tags = 0;
697 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
698 return die_("during FLAC::Metadata::get_tags()");
700 /* check to see if some basic data matches (c.f. generate_file_()) */
701 if(tags->get_num_comments() != 0)
702 return die_("mismatch in tags->get_num_comments()");
710 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
712 FLAC::Metadata::VorbisComment tags;
714 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
715 return die_("during FLAC::Metadata::get_tags()");
717 /* check to see if some basic data matches (c.f. generate_file_()) */
718 if(tags.get_num_comments() != 0)
719 return die_("mismatch in tags.get_num_comments()");
725 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
727 FLAC::Metadata::CueSheet *cuesheet = 0;
729 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
730 return die_("during FLAC::Metadata::get_cuesheet()");
732 /* check to see if some basic data matches (c.f. generate_file_()) */
733 if(cuesheet->get_lead_in() != 123)
734 return die_("mismatch in cuesheet->get_lead_in()");
742 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
744 FLAC::Metadata::CueSheet cuesheet;
746 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
747 return die_("during FLAC::Metadata::get_cuesheet()");
749 /* check to see if some basic data matches (c.f. generate_file_()) */
750 if(cuesheet.get_lead_in() != 123)
751 return die_("mismatch in cuesheet.get_lead_in()");
757 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
759 FLAC::Metadata::Picture *picture = 0;
761 if(!FLAC::Metadata::get_picture(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)))
762 return die_("during FLAC::Metadata::get_picture()");
764 /* check to see if some basic data matches (c.f. generate_file_()) */
765 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
766 return die_("mismatch in picture->get_type ()");
774 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
776 FLAC::Metadata::Picture picture;
778 if(!FLAC::Metadata::get_picture(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)))
779 return die_("during FLAC::Metadata::get_picture()");
781 /* check to see if some basic data matches (c.f. generate_file_()) */
782 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
783 return die_("mismatch in picture->get_type ()");
788 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
794 static bool test_level_1_()
796 FLAC::Metadata::Prototype *block;
797 FLAC::Metadata::StreamInfo *streaminfo;
798 FLAC::Metadata::Padding *padding;
799 FLAC::Metadata::Application *app;
800 FLAC__byte data[1000];
801 unsigned our_current_position = 0;
803 // initialize 'data' to avoid Valgrind errors
804 memset(data, 0, sizeof(data));
806 printf("\n\n++++++ testing level 1 interface\n");
808 /************************************************************/
810 printf("simple iterator on read-only file\n");
812 if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
815 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
818 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
821 FLAC::Metadata::SimpleIterator iterator;
823 if(!iterator.is_valid())
824 return die_("iterator.is_valid() returned false");
826 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
827 return die_("iterator.init() returned false");
829 printf("is writable = %u\n", (unsigned)iterator.is_writable());
830 if(iterator.is_writable())
831 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
833 printf("iterate forwards\n");
835 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
836 return die_("expected STREAMINFO type from iterator.get_block_type()");
837 if(0 == (block = iterator.get_block()))
838 return die_("getting block 0");
839 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
840 return die_("expected STREAMINFO type");
841 if(block->get_is_last())
842 return die_("expected is_last to be false");
843 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
844 return die_("bad STREAMINFO length");
845 /* check to see if some basic data matches (c.f. generate_file_()) */
846 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
847 FLAC__ASSERT(0 != streaminfo);
848 if(streaminfo->get_channels() != 1)
849 return die_("mismatch in channels");
850 if(streaminfo->get_bits_per_sample() != 8)
851 return die_("mismatch in bits_per_sample");
852 if(streaminfo->get_sample_rate() != 44100)
853 return die_("mismatch in sample_rate");
854 if(streaminfo->get_min_blocksize() != 576)
855 return die_("mismatch in min_blocksize");
856 if(streaminfo->get_max_blocksize() != 576)
857 return die_("mismatch in max_blocksize");
858 // we will delete streaminfo a little later when we're really done with it...
861 return die_("forward iterator ended early");
862 our_current_position++;
865 return die_("forward iterator ended early");
866 our_current_position++;
868 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
869 return die_("expected PADDING type from iterator.get_block_type()");
870 if(0 == (block = iterator.get_block()))
871 return die_("getting block 1");
872 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
873 return die_("expected PADDING type");
874 if(!block->get_is_last())
875 return die_("expected is_last to be true");
876 /* check to see if some basic data matches (c.f. generate_file_()) */
877 if(block->get_length() != 1234)
878 return die_("bad PADDING length");
882 return die_("forward iterator returned true but should have returned false");
884 printf("iterate backwards\n");
886 return die_("reverse iterator ended early");
888 return die_("reverse iterator ended early");
890 return die_("reverse iterator returned true but should have returned false");
892 printf("testing iterator.set_block() on read-only file...\n");
894 if(!iterator.set_block(streaminfo, false))
895 printf("PASSED. iterator.set_block() returned false like it should\n");
897 return die_("iterator.set_block() returned true but shouldn't have");
901 /************************************************************/
903 printf("simple iterator on writable file\n");
905 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
908 printf("creating APPLICATION block\n");
910 if(0 == (app = new FLAC::Metadata::Application()))
911 return die_("new FLAC::Metadata::Application()");
912 app->set_id((const unsigned char *)"duh");
914 printf("creating PADDING block\n");
916 if(0 == (padding = new FLAC::Metadata::Padding()))
917 return die_("new FLAC::Metadata::Padding()");
918 padding->set_length(20);
920 FLAC::Metadata::SimpleIterator iterator;
922 if(!iterator.is_valid())
923 return die_("iterator.is_valid() returned false");
925 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
926 return die_("iterator.init() returned false");
927 our_current_position = 0;
929 printf("is writable = %u\n", (unsigned)iterator.is_writable());
931 printf("[S]VP\ttry to write over STREAMINFO block...\n");
932 if(!iterator.set_block(app, false))
933 printf("\titerator.set_block() returned false like it should\n");
935 return die_("iterator.set_block() returned true but shouldn't have");
937 printf("[S]VP\tnext\n");
939 return die_("iterator ended early\n");
940 our_current_position++;
942 printf("S[V]P\tnext\n");
944 return die_("iterator ended early\n");
945 our_current_position++;
947 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
948 padding->set_length(25);
949 if(!iterator.insert_block_after(padding, false))
950 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
951 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
954 printf("SVP[P]\tprev\n");
956 return die_("iterator ended early\n");
957 our_current_position--;
959 printf("SV[P]P\tprev\n");
961 return die_("iterator ended early\n");
962 our_current_position--;
964 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
965 padding->set_length(30);
966 if(!iterator.insert_block_after(padding, false))
967 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
968 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
971 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
974 printf("SV[P]PP\tprev\n");
976 return die_("iterator ended early\n");
977 our_current_position--;
979 printf("S[V]PPP\tprev\n");
981 return die_("iterator ended early\n");
982 our_current_position--;
984 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
985 if(iterator.delete_block(false))
986 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
988 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
991 printf("[S]VPPP\tnext\n");
993 return die_("iterator ended early\n");
994 our_current_position++;
996 printf("S[V]PPP\tnext\n");
998 return die_("iterator ended early\n");
999 our_current_position++;
1001 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
1002 if(!iterator.delete_block(true))
1003 return die_ss_("iterator.delete_block(true)", iterator);
1004 our_current_position--;
1006 printf("S[V]PPP\tnext\n");
1007 if(!iterator.next())
1008 return die_("iterator ended early\n");
1009 our_current_position++;
1011 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1012 if(!iterator.delete_block(false))
1013 return die_ss_("iterator.delete_block(false)", iterator);
1014 delete_from_our_metadata_(our_current_position--);
1016 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1019 printf("S[V]PP\tnext\n");
1020 if(!iterator.next())
1021 return die_("iterator ended early\n");
1022 our_current_position++;
1024 printf("SV[P]P\tnext\n");
1025 if(!iterator.next())
1026 return die_("iterator ended early\n");
1027 our_current_position++;
1029 printf("SVP[P]\tdelete (last block), replace with padding\n");
1030 if(!iterator.delete_block(true))
1031 return die_ss_("iterator.delete_block(false)", iterator);
1032 our_current_position--;
1034 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1037 printf("SV[P]P\tnext\n");
1038 if(!iterator.next())
1039 return die_("iterator ended early\n");
1040 our_current_position++;
1042 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1043 if(!iterator.delete_block(false))
1044 return die_ss_("iterator.delete_block(false)", iterator);
1045 delete_from_our_metadata_(our_current_position--);
1047 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1050 printf("SV[P]\tprev\n");
1051 if(!iterator.prev())
1052 return die_("iterator ended early\n");
1053 our_current_position--;
1055 printf("S[V]P\tprev\n");
1056 if(!iterator.prev())
1057 return die_("iterator ended early\n");
1058 our_current_position--;
1060 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1061 FLAC__ASSERT(our_current_position == 0);
1062 block = iterator.get_block();
1063 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1064 FLAC__ASSERT(0 != streaminfo);
1065 streaminfo->set_sample_rate(32000);
1066 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1067 return die_("copying object");
1068 if(!iterator.set_block(block, false))
1069 return die_ss_("iterator.set_block(block, false)", iterator);
1072 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1075 printf("[S]VP\tnext\n");
1076 if(!iterator.next())
1077 return die_("iterator ended early\n");
1078 our_current_position++;
1080 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1081 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1082 if(!iterator.insert_block_after(app, true))
1083 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1084 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1086 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1088 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1091 printf("SV[A]P\tnext\n");
1092 if(!iterator.next())
1093 return die_("iterator ended early\n");
1094 our_current_position++;
1096 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1097 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1098 if(!iterator.set_block(app, true))
1099 return die_ss_("iterator.set_block(app, true)", iterator);
1100 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1102 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1104 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1107 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1108 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1109 if(!app->set_data(data, sizeof(data), true))
1110 return die_("setting APPLICATION data");
1111 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1112 return die_("copying object");
1113 if(!iterator.set_block(app, false))
1114 return die_ss_("iterator.set_block(app, false)", iterator);
1116 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1119 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1120 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1121 if(!app->set_data(data, 12, true))
1122 return die_("setting APPLICATION data");
1123 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1124 return die_("copying object");
1125 if(!iterator.set_block(app, false))
1126 return die_ss_("iterator.set_block(app, false)", iterator);
1128 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1131 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1132 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1133 if(!app->set_data(data, sizeof(data), true))
1134 return die_("setting APPLICATION data");
1135 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1136 return die_("copying object");
1137 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1138 if(!iterator.set_block(app, true))
1139 return die_ss_("iterator.set_block(app, true)", iterator);
1141 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1144 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1145 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1146 if(!app->set_data(data, 23, true))
1147 return die_("setting APPLICATION data");
1148 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1149 return die_("copying object");
1150 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1151 return die_("copying object");
1152 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1153 if(!iterator.set_block(app, true))
1154 return die_ss_("iterator.set_block(app, true)", iterator);
1156 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1159 printf("SVA[A]PP\tnext\n");
1160 if(!iterator.next())
1161 return die_("iterator ended early\n");
1162 our_current_position++;
1164 printf("SVAA[P]P\tnext\n");
1165 if(!iterator.next())
1166 return die_("iterator ended early\n");
1167 our_current_position++;
1169 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1170 padding->set_length(5);
1171 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1172 return die_("copying object");
1173 if(!iterator.set_block(padding, false))
1174 return die_ss_("iterator.set_block(padding, false)", iterator);
1176 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1179 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1180 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1181 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1182 return die_("copying object");
1183 if(!iterator.set_block(app, false))
1184 return die_ss_("iterator.set_block(app, false)", iterator);
1186 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1189 printf("SVAAP[A]\tset PADDING (equal)\n");
1190 padding->set_length(27);
1191 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1192 return die_("copying object");
1193 if(!iterator.set_block(padding, false))
1194 return die_ss_("iterator.set_block(padding, false)", iterator);
1196 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1199 printf("SVAAP[P]\tprev\n");
1200 if(!iterator.prev())
1201 return die_("iterator ended early\n");
1202 our_current_position--;
1204 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1205 if(!iterator.delete_block(false))
1206 return die_ss_("iterator.delete_block(false)", iterator);
1207 delete_from_our_metadata_(our_current_position--);
1209 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1212 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1213 if(!iterator.delete_block(false))
1214 return die_ss_("iterator.delete_block(false)", iterator);
1215 delete_from_our_metadata_(our_current_position--);
1217 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1220 printf("SV[A]P\tnext\n");
1221 if(!iterator.next())
1222 return die_("iterator ended early\n");
1223 our_current_position++;
1225 printf("SVA[P]\tinsert PADDING after\n");
1226 padding->set_length(5);
1227 if(!iterator.insert_block_after(padding, false))
1228 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1229 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1232 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1235 printf("SVAP[P]\tprev\n");
1236 if(!iterator.prev())
1237 return die_("iterator ended early\n");
1238 our_current_position--;
1240 printf("SVA[P]P\tprev\n");
1241 if(!iterator.prev())
1242 return die_("iterator ended early\n");
1243 our_current_position--;
1245 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1246 if(!app->set_data(data, 32, true))
1247 return die_("setting APPLICATION data");
1248 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1249 return die_("copying object");
1250 if(!iterator.set_block(app, true))
1251 return die_ss_("iterator.set_block(app, true)", iterator);
1253 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1256 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1257 if(!app->set_data(data, 60, true))
1258 return die_("setting APPLICATION data");
1259 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1260 return die_("copying object");
1261 if(!iterator.set_block(app, true))
1262 return die_ss_("iterator.set_block(app, true)", iterator);
1264 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1267 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1268 if(!app->set_data(data, 87, true))
1269 return die_("setting APPLICATION data");
1270 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1271 return die_("copying object");
1272 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1273 if(!iterator.set_block(app, true))
1274 return die_ss_("iterator.set_block(app, true)", iterator);
1276 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1279 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1280 if(!app->set_data(data, 91, true))
1281 return die_("setting APPLICATION data");
1282 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1283 return die_("copying object");
1284 delete_from_our_metadata_(our_current_position+1);
1285 if(!iterator.set_block(app, true))
1286 return die_ss_("iterator.set_block(app, true)", iterator);
1288 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1291 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1292 if(!app->set_data(data, 100, true))
1293 return die_("setting APPLICATION data");
1294 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1295 return die_("copying object");
1296 delete_from_our_metadata_(our_current_position+1);
1297 our_metadata_.blocks[our_current_position]->set_is_last(true);
1298 if(!iterator.set_block(app, true))
1299 return die_ss_("iterator.set_block(app, true)", iterator);
1301 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1304 printf("SV[A]\tset PADDING (equal size)\n");
1305 padding->set_length(app->get_length());
1306 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1307 return die_("copying object");
1308 if(!iterator.set_block(padding, true))
1309 return die_ss_("iterator.set_block(padding, true)", iterator);
1311 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1314 printf("SV[P]\tinsert PADDING after\n");
1315 if(!iterator.insert_block_after(padding, false))
1316 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1317 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1320 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1323 printf("SVP[P]\tinsert PADDING after\n");
1324 padding->set_length(5);
1325 if(!iterator.insert_block_after(padding, false))
1326 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1327 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1330 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1333 printf("SVPP[P]\tprev\n");
1334 if(!iterator.prev())
1335 return die_("iterator ended early\n");
1336 our_current_position--;
1338 printf("SVP[P]P\tprev\n");
1339 if(!iterator.prev())
1340 return die_("iterator ended early\n");
1341 our_current_position--;
1343 printf("SV[P]PP\tprev\n");
1344 if(!iterator.prev())
1345 return die_("iterator ended early\n");
1346 our_current_position--;
1348 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1349 if(!app->set_data(data, 101, true))
1350 return die_("setting APPLICATION data");
1351 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1352 return die_("copying object");
1353 if(!iterator.insert_block_after(app, true))
1354 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1356 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1359 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1360 if(!iterator.delete_block(false))
1361 return die_ss_("iterator.delete_block(false)", iterator);
1362 delete_from_our_metadata_(our_current_position--);
1364 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1367 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1368 if(!app->set_data(data, 97, true))
1369 return die_("setting APPLICATION data");
1370 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1371 return die_("copying object");
1372 if(!iterator.insert_block_after(app, true))
1373 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1375 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1378 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1379 if(!iterator.delete_block(false))
1380 return die_ss_("iterator.delete_block(false)", iterator);
1381 delete_from_our_metadata_(our_current_position--);
1383 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1386 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1387 if(!app->set_data(data, 100, true))
1388 return die_("setting APPLICATION data");
1389 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1390 return die_("copying object");
1391 delete_from_our_metadata_(our_current_position+1);
1392 if(!iterator.insert_block_after(app, true))
1393 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1395 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1398 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1399 if(!iterator.delete_block(false))
1400 return die_ss_("iterator.delete_block(false)", iterator);
1401 delete_from_our_metadata_(our_current_position--);
1403 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1406 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1407 if(!app->set_data(data, 96, true))
1408 return die_("setting APPLICATION data");
1409 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1410 return die_("copying object");
1411 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1412 if(!iterator.insert_block_after(app, true))
1413 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1415 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1418 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1419 if(!iterator.delete_block(false))
1420 return die_ss_("iterator.delete_block(false)", iterator);
1421 delete_from_our_metadata_(our_current_position--);
1423 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1426 printf("S[V]PP\tnext\n");
1427 if(!iterator.next())
1428 return die_("iterator ended early\n");
1429 our_current_position++;
1431 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1432 if(!iterator.delete_block(false))
1433 return die_ss_("iterator.delete_block(false)", iterator);
1434 delete_from_our_metadata_(our_current_position--);
1436 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1439 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1440 if(!app->set_data(data, 1, true))
1441 return die_("setting APPLICATION data");
1442 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1443 return die_("copying object");
1444 delete_from_our_metadata_(our_current_position+1);
1445 if(!iterator.insert_block_after(app, true))
1446 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1448 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1455 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1461 static bool test_level_2_(bool filename_based, bool is_ogg)
1463 FLAC::Metadata::Prototype *block;
1464 FLAC::Metadata::StreamInfo *streaminfo;
1465 FLAC::Metadata::Application *app;
1466 FLAC::Metadata::Padding *padding;
1467 FLAC__byte data[2000];
1468 unsigned our_current_position;
1470 // initialize 'data' to avoid Valgrind errors
1471 memset(data, 0, sizeof(data));
1473 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1475 printf("generate read-only file\n");
1477 if(!generate_file_(/*include_extras=*/false, is_ogg))
1480 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1483 printf("create chain\n");
1484 FLAC::Metadata::Chain chain;
1485 if(!chain.is_valid())
1486 return die_("allocating memory for chain");
1488 printf("read chain\n");
1490 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1491 return die_c_("reading chain", chain.status());
1493 printf("[S]VP\ttest initial metadata\n");
1495 if(!compare_chain_(chain, 0, 0))
1497 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1503 printf("switch file to read-write\n");
1505 if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1508 printf("create iterator\n");
1510 FLAC::Metadata::Iterator iterator;
1511 if(!iterator.is_valid())
1512 return die_("allocating memory for iterator");
1514 our_current_position = 0;
1516 iterator.init(chain);
1518 if(0 == (block = iterator.get_block()))
1519 return die_("getting block from iterator");
1521 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1523 printf("[S]VP\tmodify STREAMINFO, write\n");
1525 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1526 FLAC__ASSERT(0 != streaminfo);
1527 streaminfo->set_sample_rate(32000);
1528 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1529 return die_("copying object");
1532 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1533 return die_c_("during chain.write(false, true)", chain.status());
1534 block = iterator.get_block();
1535 if(!compare_chain_(chain, our_current_position, block))
1538 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1541 printf("[S]VP\tnext\n");
1542 if(!iterator.next())
1543 return die_("iterator ended early\n");
1544 our_current_position++;
1546 printf("S[V]P\tnext\n");
1547 if(!iterator.next())
1548 return die_("iterator ended early\n");
1549 our_current_position++;
1551 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1552 if(0 == (block = iterator.get_block()))
1553 return die_("getting block from iterator");
1554 if(0 == (app = new FLAC::Metadata::Application()))
1555 return die_("new FLAC::Metadata::Application()");
1556 app->set_id((const unsigned char *)"duh");
1557 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1558 return die_("setting APPLICATION data");
1560 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1561 return die_("copying object");
1562 if(!iterator.set_block(app))
1563 return die_c_("iterator.set_block(app)", chain.status());
1565 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1566 return die_c_("during chain.write(false, false)", chain.status());
1567 block = iterator.get_block();
1568 if(!compare_chain_(chain, our_current_position, block))
1571 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1574 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1575 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1576 return die_("copying object");
1577 if(!app->set_data(data, 26, true))
1578 return die_("setting APPLICATION data");
1579 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1580 return die_("copying object");
1581 if(!iterator.set_block(app))
1582 return die_c_("iterator.set_block(app)", chain.status());
1584 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1585 return die_c_("during chain.write(false, false)", chain.status());
1586 block = iterator.get_block();
1587 if(!compare_chain_(chain, our_current_position, block))
1590 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1593 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1594 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1595 return die_("copying object");
1596 if(!app->set_data(data, 28, true))
1597 return die_("setting APPLICATION data");
1598 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1599 return die_("copying object");
1600 if(!iterator.set_block(app))
1601 return die_c_("iterator.set_block(app)", chain.status());
1603 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1604 return die_c_("during chain.write(false, false)", chain.status());
1605 block = iterator.get_block();
1606 if(!compare_chain_(chain, our_current_position, block))
1609 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1612 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1613 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1614 return die_("copying object");
1615 if(!app->set_data(data, 36, true))
1616 return die_("setting APPLICATION data");
1617 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1618 return die_("copying object");
1619 if(!iterator.set_block(app))
1620 return die_c_("iterator.set_block(app)", chain.status());
1622 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1623 return die_c_("during chain.write(false, false)", chain.status());
1624 block = iterator.get_block();
1625 if(!compare_chain_(chain, our_current_position, block))
1628 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1631 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1632 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1633 return die_("copying object");
1634 if(!app->set_data(data, 33, true))
1635 return die_("setting APPLICATION data");
1636 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1637 return die_("copying object");
1638 if(!iterator.set_block(app))
1639 return die_c_("iterator.set_block(app)", chain.status());
1641 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1642 return die_c_("during chain.write(true, false)", chain.status());
1643 block = iterator.get_block();
1644 if(!compare_chain_(chain, our_current_position, block))
1647 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1650 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1651 if(0 == (padding = new FLAC::Metadata::Padding()))
1652 return die_("creating PADDING block");
1653 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1654 return die_("copying object");
1655 if(!app->set_data(data, 29, true))
1656 return die_("setting APPLICATION data");
1657 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1658 return die_("copying object");
1659 padding->set_length(0);
1660 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1661 return die_("internal error");
1662 if(!iterator.set_block(app))
1663 return die_c_("iterator.set_block(app)", chain.status());
1665 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1666 return die_c_("during chain.write(true, false)", chain.status());
1667 block = iterator.get_block();
1668 if(!compare_chain_(chain, our_current_position, block))
1671 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1674 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1675 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1676 return die_("copying object");
1677 if(!app->set_data(data, 16, true))
1678 return die_("setting APPLICATION data");
1679 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1680 return die_("copying object");
1681 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1682 if(!iterator.set_block(app))
1683 return die_c_("iterator.set_block(app)", chain.status());
1685 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1686 return die_c_("during chain.write(true, false)", chain.status());
1687 block = iterator.get_block();
1688 if(!compare_chain_(chain, our_current_position, block))
1691 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1694 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1695 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1696 return die_("copying object");
1697 if(!app->set_data(data, 50, true))
1698 return die_("setting APPLICATION data");
1699 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1700 return die_("copying object");
1701 if(!iterator.set_block(app))
1702 return die_c_("iterator.set_block(app)", chain.status());
1704 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1705 return die_c_("during chain.write(true, false)", chain.status());
1706 block = iterator.get_block();
1707 if(!compare_chain_(chain, our_current_position, block))
1710 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1713 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1714 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1715 return die_("copying object");
1716 if(!app->set_data(data, 56, true))
1717 return die_("setting APPLICATION data");
1718 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1719 return die_("copying object");
1720 add_to_padding_length_(our_current_position+1, -(56 - 50));
1721 if(!iterator.set_block(app))
1722 return die_c_("iterator.set_block(app)", chain.status());
1724 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1725 return die_c_("during chain.write(true, false)", chain.status());
1726 block = iterator.get_block();
1727 if(!compare_chain_(chain, our_current_position, block))
1730 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1733 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1734 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1735 return die_("copying object");
1736 if(!app->set_data(data, 67, true))
1737 return die_("setting APPLICATION data");
1738 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1739 return die_("copying object");
1740 delete_from_our_metadata_(our_current_position+1);
1741 if(!iterator.set_block(app))
1742 return die_c_("iterator.set_block(app)", chain.status());
1744 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1745 return die_c_("during chain.write(true, false)", chain.status());
1746 block = iterator.get_block();
1747 if(!compare_chain_(chain, our_current_position, block))
1750 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1753 printf("SV[A]\tprev\n");
1754 if(!iterator.prev())
1755 return die_("iterator ended early\n");
1756 our_current_position--;
1758 printf("S[V]A\tprev\n");
1759 if(!iterator.prev())
1760 return die_("iterator ended early\n");
1761 our_current_position--;
1763 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1764 if(0 == (padding = new FLAC::Metadata::Padding()))
1765 return die_("creating PADDING block");
1766 padding->set_length(30);
1767 if(!iterator.insert_block_before(padding))
1768 printf("\titerator.insert_block_before() returned false like it should\n");
1770 return die_("iterator.insert_block_before() should have returned false");
1772 printf("[S]VA\tnext\n");
1773 if(!iterator.next())
1774 return die_("iterator ended early\n");
1775 our_current_position++;
1777 printf("S[V]A\tinsert PADDING after\n");
1778 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1779 return die_("copying metadata");
1780 if(!iterator.insert_block_after(padding))
1781 return die_("iterator.insert_block_after(padding)");
1783 block = iterator.get_block();
1784 if(!compare_chain_(chain, our_current_position, block))
1788 printf("SV[P]A\tinsert PADDING before\n");
1789 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1790 return die_("creating PADDING block");
1791 padding->set_length(17);
1792 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1793 return die_("copying metadata");
1794 if(!iterator.insert_block_before(padding))
1795 return die_("iterator.insert_block_before(padding)");
1797 block = iterator.get_block();
1798 if(!compare_chain_(chain, our_current_position, block))
1802 printf("SV[P]PA\tinsert PADDING before\n");
1803 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1804 return die_("creating PADDING block");
1805 padding->set_length(0);
1806 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1807 return die_("copying metadata");
1808 if(!iterator.insert_block_before(padding))
1809 return die_("iterator.insert_block_before(padding)");
1811 block = iterator.get_block();
1812 if(!compare_chain_(chain, our_current_position, block))
1816 printf("SV[P]PPA\tnext\n");
1817 if(!iterator.next())
1818 return die_("iterator ended early\n");
1819 our_current_position++;
1821 printf("SVP[P]PA\tnext\n");
1822 if(!iterator.next())
1823 return die_("iterator ended early\n");
1824 our_current_position++;
1826 printf("SVPP[P]A\tnext\n");
1827 if(!iterator.next())
1828 return die_("iterator ended early\n");
1829 our_current_position++;
1831 printf("SVPPP[A]\tinsert PADDING after\n");
1832 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1833 return die_("creating PADDING block");
1834 padding->set_length(57);
1835 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1836 return die_("copying metadata");
1837 if(!iterator.insert_block_after(padding))
1838 return die_("iterator.insert_block_after(padding)");
1840 block = iterator.get_block();
1841 if(!compare_chain_(chain, our_current_position, block))
1845 printf("SVPPPA[P]\tinsert PADDING before\n");
1846 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1847 return die_("creating PADDING block");
1848 padding->set_length(99);
1849 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1850 return die_("copying metadata");
1851 if(!iterator.insert_block_before(padding))
1852 return die_("iterator.insert_block_before(padding)");
1854 block = iterator.get_block();
1855 if(!compare_chain_(chain, our_current_position, block))
1860 our_current_position = 0;
1862 printf("SVPPPAPP\tmerge padding\n");
1863 chain.merge_padding();
1864 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1865 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1866 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1867 delete_from_our_metadata_(7);
1868 delete_from_our_metadata_(4);
1869 delete_from_our_metadata_(3);
1871 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1872 return die_c_("during chain.write(true, false)", chain.status());
1873 if(!compare_chain_(chain, 0, 0))
1875 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1878 printf("SVPAP\tsort padding\n");
1879 chain.sort_padding();
1880 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1881 delete_from_our_metadata_(2);
1883 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1884 return die_c_("during chain.write(true, false)", chain.status());
1885 if(!compare_chain_(chain, 0, 0))
1887 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1890 printf("create iterator\n");
1892 FLAC::Metadata::Iterator iterator;
1893 if(!iterator.is_valid())
1894 return die_("allocating memory for iterator");
1896 our_current_position = 0;
1898 iterator.init(chain);
1900 printf("[S]VAP\tnext\n");
1901 if(!iterator.next())
1902 return die_("iterator ended early\n");
1903 our_current_position++;
1905 printf("S[V]AP\tnext\n");
1906 if(!iterator.next())
1907 return die_("iterator ended early\n");
1908 our_current_position++;
1910 printf("SV[A]P\tdelete middle block, replace with padding\n");
1911 if(0 == (padding = new FLAC::Metadata::Padding()))
1912 return die_("creating PADDING block");
1913 padding->set_length(71);
1914 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1915 return die_("copying object");
1916 if(!iterator.delete_block(/*replace_with_padding=*/true))
1917 return die_c_("iterator.delete_block(true)", chain.status());
1919 block = iterator.get_block();
1920 if(!compare_chain_(chain, our_current_position, block))
1924 printf("S[V]PP\tnext\n");
1925 if(!iterator.next())
1926 return die_("iterator ended early\n");
1927 our_current_position++;
1929 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1930 delete_from_our_metadata_(our_current_position--);
1931 if(!iterator.delete_block(/*replace_with_padding=*/false))
1932 return die_c_("iterator.delete_block(false)", chain.status());
1934 block = iterator.get_block();
1935 if(!compare_chain_(chain, our_current_position, block))
1939 printf("S[V]P\tnext\n");
1940 if(!iterator.next())
1941 return die_("iterator ended early\n");
1942 our_current_position++;
1944 printf("SV[P]\tdelete last block, replace with padding\n");
1945 if(0 == (padding = new FLAC::Metadata::Padding()))
1946 return die_("creating PADDING block");
1947 padding->set_length(219);
1948 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1949 return die_("copying object");
1950 if(!iterator.delete_block(/*replace_with_padding=*/true))
1951 return die_c_("iterator.delete_block(true)", chain.status());
1953 block = iterator.get_block();
1954 if(!compare_chain_(chain, our_current_position, block))
1958 printf("S[V]P\tnext\n");
1959 if(!iterator.next())
1960 return die_("iterator ended early\n");
1961 our_current_position++;
1963 printf("SV[P]\tdelete last block, don't replace with padding\n");
1964 delete_from_our_metadata_(our_current_position--);
1965 if(!iterator.delete_block(/*replace_with_padding=*/false))
1966 return die_c_("iterator.delete_block(false)", chain.status());
1968 block = iterator.get_block();
1969 if(!compare_chain_(chain, our_current_position, block))
1973 printf("S[V]\tprev\n");
1974 if(!iterator.prev())
1975 return die_("iterator ended early\n");
1976 our_current_position--;
1978 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1979 if(iterator.delete_block(/*replace_with_padding=*/false))
1980 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1982 block = iterator.get_block();
1983 if(!compare_chain_(chain, our_current_position, block))
1987 } // delete iterator
1988 our_current_position = 0;
1990 printf("SV\tmerge padding\n");
1991 chain.merge_padding();
1993 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1994 return die_c_("during chain.write(false, false)", chain.status());
1995 if(!compare_chain_(chain, 0, 0))
1997 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2000 printf("SV\tsort padding\n");
2001 chain.sort_padding();
2003 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
2004 return die_c_("during chain.write(false, false)", chain.status());
2005 if(!compare_chain_(chain, 0, 0))
2007 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2011 if(!remove_file_(flacfilename(is_ogg)))
2017 static bool test_level_2_misc_(bool is_ogg)
2019 ::FLAC__IOCallbacks callbacks;
2021 memset(&callbacks, 0, sizeof(callbacks));
2022 callbacks.read = (::FLAC__IOCallback_Read)fread;
2023 #ifdef FLAC__VALGRIND_TESTING
2024 callbacks.write = chain_write_cb_;
2026 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2028 callbacks.seek = chain_seek_cb_;
2029 callbacks.tell = chain_tell_cb_;
2030 callbacks.eof = chain_eof_cb_;
2032 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2034 printf("generate file\n");
2036 if(!generate_file_(/*include_extras=*/false, is_ogg))
2039 printf("create chain\n");
2040 FLAC::Metadata::Chain chain;
2041 if(!chain.is_valid())
2042 return die_("allocating chain");
2044 printf("read chain (filename-based)\n");
2046 if(!chain.read(flacfilename(is_ogg)))
2047 return die_c_("reading chain", chain.status());
2049 printf("write chain with wrong method Chain::write(with callbacks)\n");
2051 if(chain.write(/*use_padding=*/false, 0, callbacks))
2052 return die_c_("mismatched write should have failed", chain.status());
2053 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2054 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2055 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2058 printf("read chain (filename-based)\n");
2060 if(!chain.read(flacfilename(is_ogg)))
2061 return die_c_("reading chain", chain.status());
2063 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2065 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2066 return die_c_("mismatched write should have failed", chain.status());
2067 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2068 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2069 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2072 printf("read chain (callback-based)\n");
2074 FILE *file = fopen(flacfilename(is_ogg), "rb");
2076 return die_("opening file");
2077 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2079 return die_c_("reading chain", chain.status());
2084 printf("write chain with wrong method write()\n");
2086 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2087 return die_c_("mismatched write should have failed", chain.status());
2088 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2089 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2090 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2093 printf("read chain (callback-based)\n");
2095 FILE *file = fopen(flacfilename(is_ogg), "rb");
2097 return die_("opening file");
2098 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2100 return die_c_("reading chain", chain.status());
2105 printf("testing Chain::check_if_tempfile_needed()... ");
2107 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2108 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2110 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2112 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2114 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2115 return die_c_("mismatched write should have failed", chain.status());
2116 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2117 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2118 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2121 printf("read chain (callback-based)\n");
2123 FILE *file = fopen(flacfilename(is_ogg), "rb");
2125 return die_("opening file");
2126 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2128 return die_c_("reading chain", chain.status());
2133 printf("create iterator\n");
2135 FLAC::Metadata::Iterator iterator;
2136 if(!iterator.is_valid())
2137 return die_("allocating memory for iterator");
2139 iterator.init(chain);
2141 printf("[S]VP\tnext\n");
2142 if(!iterator.next())
2143 return die_("iterator ended early\n");
2145 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2146 if(!iterator.delete_block(/*replace_with_padding=*/false))
2147 return die_c_("block delete failed\n", chain.status());
2149 printf("testing Chain::check_if_tempfile_needed()... ");
2151 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2152 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2154 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2156 printf("write chain with wrong method Chain::write(with callbacks)\n");
2158 if(chain.write(/*use_padding=*/false, 0, callbacks))
2159 return die_c_("mismatched write should have failed", chain.status());
2160 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2161 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2162 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2165 } // delete iterator
2167 if(!remove_file_(flacfilename(is_ogg)))
2173 bool test_metadata_file_manipulation()
2175 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2177 our_metadata_.num_blocks = 0;
2179 if(!test_level_0_())
2182 if(!test_level_1_())
2185 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2187 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2189 if(!test_level_2_misc_(/*is_ogg=*/false))
2192 if(FLAC_API_SUPPORTS_OGG_FLAC) {
2193 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2195 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2198 /* when ogg flac write is supported, will have to add this: */
2199 if(!test_level_2_misc_(/*is_ogg=*/true))