1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <stdlib.h> /* for malloc() */
25 #include <string.h> /* for memcpy()/memset() */
26 #if defined _MSC_VER || defined __MINGW32__
27 #include <sys/utime.h> /* for utime() */
28 #include <io.h> /* for chmod() */
29 #if _MSC_VER <= 1200 /* @@@ [2G limit] */
34 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
35 #include <utime.h> /* for utime() */
36 #include <unistd.h> /* for chown(), unlink() */
38 #include <sys/stat.h> /* for stat(), maybe chmod() */
39 #include "FLAC/assert.h"
40 #include "FLAC++/decoder.h"
41 #include "FLAC++/metadata.h"
42 #include "share/grabbag.h"
44 #include "test_libs_common/file_utils_flac.h"
47 /******************************************************************************
48 The general strategy of these tests (for interface levels 1 and 2) is
49 to create a dummy FLAC file with a known set of initial metadata
50 blocks, then keep a mirror locally of what we expect the metadata to be
51 after each operation. Then testing becomes a simple matter of running
52 a FLAC::Decoder::File over the dummy file after each operation, comparing
53 the decoded metadata to what's in our local copy. If there are any
54 differences in the metadata, or the actual audio data is corrupted, we
55 will catch it while decoding.
56 ******************************************************************************/
58 class OurFileDecoder: public FLAC::Decoder::File {
60 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
62 bool ignore_metadata_;
65 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
66 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
67 void error_callback(::FLAC__StreamDecoderErrorStatus status);
71 FLAC::Metadata::Prototype *blocks[64];
75 /* our copy of the metadata in flacfilename() */
76 static OurMetadata our_metadata_;
78 /* the current block number that corresponds to the position of the iterator we are testing */
79 static unsigned mc_our_block_number_ = 0;
81 static const char *flacfilename(bool is_ogg)
83 return is_ogg? "metadata.ogg" : "metadata.flac";
86 static bool die_(const char *msg)
88 printf("ERROR: %s\n", msg);
92 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
94 printf("ERROR: %s\n", msg);
95 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
99 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
101 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
102 printf("ERROR: %s\n", msg);
103 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
107 static void *malloc_or_die_(size_t size)
109 void *x = malloc(size);
111 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
117 static char *strdup_or_die_(const char *s)
121 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
127 /* functions for working with our metadata copy */
129 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
132 FLAC::Metadata::Prototype *obj = block;
133 FLAC__ASSERT(position < our_metadata_.num_blocks);
135 if(0 == (obj = FLAC::Metadata::clone(block)))
136 return die_("during FLAC::Metadata::clone()");
138 delete our_metadata_.blocks[position];
139 our_metadata_.blocks[position] = obj;
141 /* set the is_last flags */
142 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
143 our_metadata_.blocks[i]->set_is_last(false);
144 our_metadata_.blocks[i]->set_is_last(true);
149 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
152 FLAC::Metadata::Prototype *obj = block;
154 if(0 == (obj = FLAC::Metadata::clone(block)))
155 return die_("during FLAC::Metadata::clone()");
157 if(position > our_metadata_.num_blocks) {
158 position = our_metadata_.num_blocks;
161 for(i = our_metadata_.num_blocks; i > position; i--)
162 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
164 our_metadata_.blocks[position] = obj;
165 our_metadata_.num_blocks++;
167 /* set the is_last flags */
168 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
169 our_metadata_.blocks[i]->set_is_last(false);
170 our_metadata_.blocks[i]->set_is_last(true);
175 static void delete_from_our_metadata_(unsigned position)
178 FLAC__ASSERT(position < our_metadata_.num_blocks);
179 delete our_metadata_.blocks[position];
180 for(i = position; i < our_metadata_.num_blocks - 1; i++)
181 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
182 our_metadata_.num_blocks--;
184 /* set the is_last flags */
185 if(our_metadata_.num_blocks > 0) {
186 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
187 our_metadata_.blocks[i]->set_is_last(false);
188 our_metadata_.blocks[i]->set_is_last(true);
192 void add_to_padding_length_(unsigned index, int delta)
194 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
195 FLAC__ASSERT(0 != padding);
196 padding->set_length((unsigned)((int)padding->get_length() + delta));
200 * This wad of functions supports filename- and callback-based chain reading/writing.
201 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
203 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
205 static const char *tempfile_suffix = ".metadata_edit";
207 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
209 strcpy(*tempfilename, filename);
210 strcat(*tempfilename, tempfile_suffix);
212 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
218 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
221 (void)fclose(*tempfile);
225 if(0 != *tempfilename) {
226 (void)unlink(*tempfilename);
232 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
234 FLAC__ASSERT(0 != filename);
235 FLAC__ASSERT(0 != tempfile);
236 FLAC__ASSERT(0 != tempfilename);
237 FLAC__ASSERT(0 != *tempfilename);
240 (void)fclose(*tempfile);
244 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
245 /* on some flavors of windows, rename() will fail if the destination already exists */
246 if(unlink(filename) < 0) {
247 cleanup_tempfile_(tempfile, tempfilename);
252 if(0 != rename(*tempfilename, filename)) {
253 cleanup_tempfile_(tempfile, tempfilename);
257 cleanup_tempfile_(tempfile, tempfilename);
262 bool get_file_stats_(const char *filename, struct stat *stats)
264 FLAC__ASSERT(0 != filename);
265 FLAC__ASSERT(0 != stats);
266 return (0 == stat(filename, stats));
269 void set_file_stats_(const char *filename, struct stat *stats)
271 struct utimbuf srctime;
273 FLAC__ASSERT(0 != filename);
274 FLAC__ASSERT(0 != stats);
276 srctime.actime = stats->st_atime;
277 srctime.modtime = stats->st_mtime;
278 (void)chmod(filename, stats->st_mode);
279 (void)utime(filename, &srctime);
280 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
281 (void)chown(filename, stats->st_uid, (gid_t)(-1));
282 (void)chown(filename, (uid_t)(-1), stats->st_gid);
286 #ifdef FLAC__VALGRIND_TESTING
287 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
289 FILE *stream = (FILE*)handle;
290 size_t ret = fwrite(ptr, size, nmemb, stream);
297 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
299 off_t o = (off_t)offset;
300 FLAC__ASSERT(offset == o);
301 return fseeko((FILE*)handle, o, whence);
304 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
306 return ftello((FILE*)handle);
309 static int chain_eof_cb_(::FLAC__IOHandle handle)
311 return feof((FILE*)handle);
314 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
317 return chain.write(use_padding, preserve_file_stats);
319 ::FLAC__IOCallbacks callbacks;
321 memset(&callbacks, 0, sizeof(callbacks));
322 callbacks.read = (::FLAC__IOCallback_Read)fread;
323 #ifdef FLAC__VALGRIND_TESTING
324 callbacks.write = chain_write_cb_;
326 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
328 callbacks.seek = chain_seek_cb_;
329 callbacks.eof = chain_eof_cb_;
331 if(chain.check_if_tempfile_needed(use_padding)) {
333 FILE *file, *tempfile;
335 if(preserve_file_stats) {
336 if(!get_file_stats_(filename, &stats))
339 if(0 == (file = fopen(filename, "rb")))
340 return false; /*@@@@ chain status still says OK though */
341 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
343 cleanup_tempfile_(&tempfile, &tempfilename);
344 return false; /*@@@@ chain status still says OK though */
346 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
354 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
356 if(preserve_file_stats)
357 set_file_stats_(filename, &stats);
360 FILE *file = fopen(filename, "r+b");
362 return false; /*@@@@ chain status still says OK though */
363 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
372 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg)
375 return chain.read(filename, is_ogg);
377 ::FLAC__IOCallbacks callbacks;
379 memset(&callbacks, 0, sizeof(callbacks));
380 callbacks.read = (::FLAC__IOCallback_Read)fread;
381 callbacks.seek = chain_seek_cb_;
382 callbacks.tell = chain_tell_cb_;
386 FILE *file = fopen(filename, "rb");
388 return false; /*@@@@ chain status still says OK though */
389 ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg);
396 /* function for comparing our metadata to a FLAC::Metadata::Chain */
398 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
401 FLAC::Metadata::Iterator iterator;
404 printf("\tcomparing chain... ");
407 if(!iterator.is_valid())
408 return die_("allocating memory for iterator");
410 iterator.init(chain);
414 FLAC::Metadata::Prototype *block;
419 if(0 == (block = iterator.get_block()))
420 return die_("getting block from iterator");
422 if(*block != *our_metadata_.blocks[i])
423 return die_("metadata block mismatch");
427 next_ok = iterator.next();
428 } while(i < our_metadata_.num_blocks && next_ok);
431 return die_("chain has more blocks than expected");
433 if(i < our_metadata_.num_blocks)
434 return die_("short block count in chain");
436 if(0 != current_block) {
437 printf("CURRENT_POSITION... ");
440 if(*current_block != *our_metadata_.blocks[current_position])
441 return die_("metadata block mismatch");
449 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
454 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
455 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
457 printf("content... ");
461 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
464 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
466 /* don't bother checking if we've already hit an error */
470 printf("%d... ", mc_our_block_number_);
473 if(!ignore_metadata_) {
474 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
475 (void)die_("got more metadata blocks than expected");
476 error_occurred_ = true;
479 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
480 (void)die_("metadata block mismatch");
481 error_occurred_ = true;
486 mc_our_block_number_++;
489 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
491 error_occurred_ = true;
492 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
495 static bool generate_file_(bool include_extras, bool is_ogg)
497 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
498 ::FLAC__StreamMetadata *metadata[4];
499 unsigned i = 0, n = 0;
501 printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
503 while(our_metadata_.num_blocks > 0)
504 delete_from_our_metadata_(0);
506 streaminfo.is_last = false;
507 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
508 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
509 streaminfo.data.stream_info.min_blocksize = 576;
510 streaminfo.data.stream_info.max_blocksize = 576;
511 streaminfo.data.stream_info.min_framesize = 0;
512 streaminfo.data.stream_info.max_framesize = 0;
513 streaminfo.data.stream_info.sample_rate = 44100;
514 streaminfo.data.stream_info.channels = 1;
515 streaminfo.data.stream_info.bits_per_sample = 8;
516 streaminfo.data.stream_info.total_samples = 0;
517 memset(streaminfo.data.stream_info.md5sum, 0, 16);
520 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
521 vorbiscomment.is_last = false;
522 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
523 vorbiscomment.length = (4 + vendor_string_length) + 4;
524 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
525 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
526 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
527 vorbiscomment.data.vorbis_comment.num_comments = 0;
528 vorbiscomment.data.vorbis_comment.comments = 0;
532 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
533 return die_("priming our metadata");
534 cuesheet->is_last = false;
535 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
536 cuesheet->data.cue_sheet.lead_in = 123;
537 cuesheet->data.cue_sheet.is_cd = false;
538 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
539 return die_("priming our metadata");
540 cuesheet->data.cue_sheet.tracks[0].number = 1;
541 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
542 return die_("priming our metadata");
546 picture.is_last = false;
547 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
550 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
551 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
552 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
553 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
554 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
555 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
556 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
557 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
560 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
561 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
562 picture.length += strlen(picture.data.picture.mime_type);
563 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
564 picture.length += strlen((const char *)picture.data.picture.description);
565 picture.data.picture.width = 300;
566 picture.data.picture.height = 300;
567 picture.data.picture.depth = 24;
568 picture.data.picture.colors = 0;
569 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
570 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
571 picture.length += picture.data.picture.data_length;
574 padding.is_last = true;
575 padding.type = ::FLAC__METADATA_TYPE_PADDING;
576 padding.length = 1234;
578 metadata[n++] = &vorbiscomment;
580 metadata[n++] = cuesheet;
581 metadata[n++] = &picture;
583 metadata[n++] = &padding;
585 FLAC::Metadata::StreamInfo s(&streaminfo);
586 FLAC::Metadata::VorbisComment v(&vorbiscomment);
587 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
588 FLAC::Metadata::Picture pi(&picture);
589 FLAC::Metadata::Padding p(&padding);
591 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
592 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
593 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
594 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
595 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
597 return die_("priming our metadata");
599 if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
600 return die_("creating the encoded file");
602 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
603 free(picture.data.picture.data);
608 static bool test_file_(bool is_ogg, bool ignore_metadata)
610 const char *filename = flacfilename(is_ogg);
611 OurFileDecoder decoder(ignore_metadata);
613 mc_our_block_number_ = 0;
614 decoder.error_occurred_ = false;
616 printf("\ttesting '%s'... ", filename);
619 if(!decoder.is_valid())
620 return die_("couldn't allocate decoder instance");
622 decoder.set_md5_checking(true);
623 decoder.set_metadata_respond_all();
624 if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
625 (void)decoder.finish();
626 return die_("initializing decoder\n");
628 if(!decoder.process_until_end_of_stream()) {
629 (void)decoder.finish();
630 return die_("decoding file\n");
633 (void)decoder.finish();
635 if(decoder.error_occurred_)
638 if(mc_our_block_number_ != our_metadata_.num_blocks)
639 return die_("short metadata block count");
645 static bool change_stats_(const char *filename, bool read_only)
647 if(!grabbag__file_change_stats(filename, read_only))
648 return die_("during grabbag__file_change_stats()");
653 static bool remove_file_(const char *filename)
655 while(our_metadata_.num_blocks > 0)
656 delete_from_our_metadata_(0);
658 if(!grabbag__file_remove_file(filename))
659 return die_("removing file");
664 static bool test_level_0_()
666 FLAC::Metadata::StreamInfo streaminfo;
668 printf("\n\n++++++ testing level 0 interface\n");
670 if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
673 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
676 printf("testing FLAC::Metadata::get_streaminfo()... ");
678 if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
679 return die_("during FLAC::Metadata::get_streaminfo()");
681 /* check to see if some basic data matches (c.f. generate_file_()) */
682 if(streaminfo.get_channels() != 1)
683 return die_("mismatch in streaminfo.get_channels()");
684 if(streaminfo.get_bits_per_sample() != 8)
685 return die_("mismatch in streaminfo.get_bits_per_sample()");
686 if(streaminfo.get_sample_rate() != 44100)
687 return die_("mismatch in streaminfo.get_sample_rate()");
688 if(streaminfo.get_min_blocksize() != 576)
689 return die_("mismatch in streaminfo.get_min_blocksize()");
690 if(streaminfo.get_max_blocksize() != 576)
691 return die_("mismatch in streaminfo.get_max_blocksize()");
696 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
698 FLAC::Metadata::VorbisComment *tags = 0;
700 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
701 return die_("during FLAC::Metadata::get_tags()");
703 /* check to see if some basic data matches (c.f. generate_file_()) */
704 if(tags->get_num_comments() != 0)
705 return die_("mismatch in tags->get_num_comments()");
713 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
715 FLAC::Metadata::VorbisComment tags;
717 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
718 return die_("during FLAC::Metadata::get_tags()");
720 /* check to see if some basic data matches (c.f. generate_file_()) */
721 if(tags.get_num_comments() != 0)
722 return die_("mismatch in tags.get_num_comments()");
728 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
730 FLAC::Metadata::CueSheet *cuesheet = 0;
732 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
733 return die_("during FLAC::Metadata::get_cuesheet()");
735 /* check to see if some basic data matches (c.f. generate_file_()) */
736 if(cuesheet->get_lead_in() != 123)
737 return die_("mismatch in cuesheet->get_lead_in()");
745 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
747 FLAC::Metadata::CueSheet cuesheet;
749 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
750 return die_("during FLAC::Metadata::get_cuesheet()");
752 /* check to see if some basic data matches (c.f. generate_file_()) */
753 if(cuesheet.get_lead_in() != 123)
754 return die_("mismatch in cuesheet.get_lead_in()");
760 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
762 FLAC::Metadata::Picture *picture = 0;
764 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)))
765 return die_("during FLAC::Metadata::get_picture()");
767 /* check to see if some basic data matches (c.f. generate_file_()) */
768 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
769 return die_("mismatch in picture->get_type ()");
777 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
779 FLAC::Metadata::Picture picture;
781 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)))
782 return die_("during FLAC::Metadata::get_picture()");
784 /* check to see if some basic data matches (c.f. generate_file_()) */
785 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
786 return die_("mismatch in picture->get_type ()");
791 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
797 static bool test_level_1_()
799 FLAC::Metadata::Prototype *block;
800 FLAC::Metadata::StreamInfo *streaminfo;
801 FLAC::Metadata::Padding *padding;
802 FLAC::Metadata::Application *app;
803 FLAC__byte data[1000];
804 unsigned our_current_position = 0;
806 // initialize 'data' to avoid Valgrind errors
807 memset(data, 0, sizeof(data));
809 printf("\n\n++++++ testing level 1 interface\n");
811 /************************************************************/
813 printf("simple iterator on read-only file\n");
815 if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
818 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
821 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
824 FLAC::Metadata::SimpleIterator iterator;
826 if(!iterator.is_valid())
827 return die_("iterator.is_valid() returned false");
829 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
830 return die_("iterator.init() returned false");
832 printf("is writable = %u\n", (unsigned)iterator.is_writable());
833 if(iterator.is_writable())
834 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
836 printf("iterate forwards\n");
838 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
839 return die_("expected STREAMINFO type from iterator.get_block_type()");
840 if(0 == (block = iterator.get_block()))
841 return die_("getting block 0");
842 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
843 return die_("expected STREAMINFO type");
844 if(block->get_is_last())
845 return die_("expected is_last to be false");
846 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
847 return die_("bad STREAMINFO length");
848 /* check to see if some basic data matches (c.f. generate_file_()) */
849 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
850 FLAC__ASSERT(0 != streaminfo);
851 if(streaminfo->get_channels() != 1)
852 return die_("mismatch in channels");
853 if(streaminfo->get_bits_per_sample() != 8)
854 return die_("mismatch in bits_per_sample");
855 if(streaminfo->get_sample_rate() != 44100)
856 return die_("mismatch in sample_rate");
857 if(streaminfo->get_min_blocksize() != 576)
858 return die_("mismatch in min_blocksize");
859 if(streaminfo->get_max_blocksize() != 576)
860 return die_("mismatch in max_blocksize");
861 // we will delete streaminfo a little later when we're really done with it...
864 return die_("forward iterator ended early");
865 our_current_position++;
868 return die_("forward iterator ended early");
869 our_current_position++;
871 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
872 return die_("expected PADDING type from iterator.get_block_type()");
873 if(0 == (block = iterator.get_block()))
874 return die_("getting block 1");
875 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
876 return die_("expected PADDING type");
877 if(!block->get_is_last())
878 return die_("expected is_last to be true");
879 /* check to see if some basic data matches (c.f. generate_file_()) */
880 if(block->get_length() != 1234)
881 return die_("bad PADDING length");
885 return die_("forward iterator returned true but should have returned false");
887 printf("iterate backwards\n");
889 return die_("reverse iterator ended early");
891 return die_("reverse iterator ended early");
893 return die_("reverse iterator returned true but should have returned false");
895 printf("testing iterator.set_block() on read-only file...\n");
897 if(!iterator.set_block(streaminfo, false))
898 printf("PASSED. iterator.set_block() returned false like it should\n");
900 return die_("iterator.set_block() returned true but shouldn't have");
904 /************************************************************/
906 printf("simple iterator on writable file\n");
908 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
911 printf("creating APPLICATION block\n");
913 if(0 == (app = new FLAC::Metadata::Application()))
914 return die_("new FLAC::Metadata::Application()");
915 app->set_id((const unsigned char *)"duh");
917 printf("creating PADDING block\n");
919 if(0 == (padding = new FLAC::Metadata::Padding()))
920 return die_("new FLAC::Metadata::Padding()");
921 padding->set_length(20);
923 FLAC::Metadata::SimpleIterator iterator;
925 if(!iterator.is_valid())
926 return die_("iterator.is_valid() returned false");
928 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
929 return die_("iterator.init() returned false");
930 our_current_position = 0;
932 printf("is writable = %u\n", (unsigned)iterator.is_writable());
934 printf("[S]VP\ttry to write over STREAMINFO block...\n");
935 if(!iterator.set_block(app, false))
936 printf("\titerator.set_block() returned false like it should\n");
938 return die_("iterator.set_block() returned true but shouldn't have");
940 printf("[S]VP\tnext\n");
942 return die_("iterator ended early\n");
943 our_current_position++;
945 printf("S[V]P\tnext\n");
947 return die_("iterator ended early\n");
948 our_current_position++;
950 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
951 padding->set_length(25);
952 if(!iterator.insert_block_after(padding, false))
953 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
954 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
957 printf("SVP[P]\tprev\n");
959 return die_("iterator ended early\n");
960 our_current_position--;
962 printf("SV[P]P\tprev\n");
964 return die_("iterator ended early\n");
965 our_current_position--;
967 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
968 padding->set_length(30);
969 if(!iterator.insert_block_after(padding, false))
970 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
971 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
974 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
977 printf("SV[P]PP\tprev\n");
979 return die_("iterator ended early\n");
980 our_current_position--;
982 printf("S[V]PPP\tprev\n");
984 return die_("iterator ended early\n");
985 our_current_position--;
987 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
988 if(iterator.delete_block(false))
989 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
991 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
994 printf("[S]VPPP\tnext\n");
996 return die_("iterator ended early\n");
997 our_current_position++;
999 printf("S[V]PPP\tnext\n");
1000 if(!iterator.next())
1001 return die_("iterator ended early\n");
1002 our_current_position++;
1004 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
1005 if(!iterator.delete_block(true))
1006 return die_ss_("iterator.delete_block(true)", iterator);
1007 our_current_position--;
1009 printf("S[V]PPP\tnext\n");
1010 if(!iterator.next())
1011 return die_("iterator ended early\n");
1012 our_current_position++;
1014 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1015 if(!iterator.delete_block(false))
1016 return die_ss_("iterator.delete_block(false)", iterator);
1017 delete_from_our_metadata_(our_current_position--);
1019 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1022 printf("S[V]PP\tnext\n");
1023 if(!iterator.next())
1024 return die_("iterator ended early\n");
1025 our_current_position++;
1027 printf("SV[P]P\tnext\n");
1028 if(!iterator.next())
1029 return die_("iterator ended early\n");
1030 our_current_position++;
1032 printf("SVP[P]\tdelete (last block), replace with padding\n");
1033 if(!iterator.delete_block(true))
1034 return die_ss_("iterator.delete_block(false)", iterator);
1035 our_current_position--;
1037 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1040 printf("SV[P]P\tnext\n");
1041 if(!iterator.next())
1042 return die_("iterator ended early\n");
1043 our_current_position++;
1045 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1046 if(!iterator.delete_block(false))
1047 return die_ss_("iterator.delete_block(false)", iterator);
1048 delete_from_our_metadata_(our_current_position--);
1050 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1053 printf("SV[P]\tprev\n");
1054 if(!iterator.prev())
1055 return die_("iterator ended early\n");
1056 our_current_position--;
1058 printf("S[V]P\tprev\n");
1059 if(!iterator.prev())
1060 return die_("iterator ended early\n");
1061 our_current_position--;
1063 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1064 FLAC__ASSERT(our_current_position == 0);
1065 block = iterator.get_block();
1066 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1067 FLAC__ASSERT(0 != streaminfo);
1068 streaminfo->set_sample_rate(32000);
1069 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1070 return die_("copying object");
1071 if(!iterator.set_block(block, false))
1072 return die_ss_("iterator.set_block(block, false)", iterator);
1075 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1078 printf("[S]VP\tnext\n");
1079 if(!iterator.next())
1080 return die_("iterator ended early\n");
1081 our_current_position++;
1083 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1084 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1085 if(!iterator.insert_block_after(app, true))
1086 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1087 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1089 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1091 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1094 printf("SV[A]P\tnext\n");
1095 if(!iterator.next())
1096 return die_("iterator ended early\n");
1097 our_current_position++;
1099 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1100 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1101 if(!iterator.set_block(app, true))
1102 return die_ss_("iterator.set_block(app, true)", iterator);
1103 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1105 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1107 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1110 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1111 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1112 if(!app->set_data(data, sizeof(data), true))
1113 return die_("setting APPLICATION data");
1114 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1115 return die_("copying object");
1116 if(!iterator.set_block(app, false))
1117 return die_ss_("iterator.set_block(app, false)", iterator);
1119 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1122 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1123 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1124 if(!app->set_data(data, 12, true))
1125 return die_("setting APPLICATION data");
1126 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1127 return die_("copying object");
1128 if(!iterator.set_block(app, false))
1129 return die_ss_("iterator.set_block(app, false)", iterator);
1131 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1134 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1135 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1136 if(!app->set_data(data, sizeof(data), true))
1137 return die_("setting APPLICATION data");
1138 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1139 return die_("copying object");
1140 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1141 if(!iterator.set_block(app, true))
1142 return die_ss_("iterator.set_block(app, true)", iterator);
1144 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1147 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1148 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1149 if(!app->set_data(data, 23, true))
1150 return die_("setting APPLICATION data");
1151 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1152 return die_("copying object");
1153 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1154 return die_("copying object");
1155 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1156 if(!iterator.set_block(app, true))
1157 return die_ss_("iterator.set_block(app, true)", iterator);
1159 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1162 printf("SVA[A]PP\tnext\n");
1163 if(!iterator.next())
1164 return die_("iterator ended early\n");
1165 our_current_position++;
1167 printf("SVAA[P]P\tnext\n");
1168 if(!iterator.next())
1169 return die_("iterator ended early\n");
1170 our_current_position++;
1172 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1173 padding->set_length(5);
1174 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1175 return die_("copying object");
1176 if(!iterator.set_block(padding, false))
1177 return die_ss_("iterator.set_block(padding, false)", iterator);
1179 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1182 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1183 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1184 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1185 return die_("copying object");
1186 if(!iterator.set_block(app, false))
1187 return die_ss_("iterator.set_block(app, false)", iterator);
1189 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1192 printf("SVAAP[A]\tset PADDING (equal)\n");
1193 padding->set_length(27);
1194 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1195 return die_("copying object");
1196 if(!iterator.set_block(padding, false))
1197 return die_ss_("iterator.set_block(padding, false)", iterator);
1199 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1202 printf("SVAAP[P]\tprev\n");
1203 if(!iterator.prev())
1204 return die_("iterator ended early\n");
1205 our_current_position--;
1207 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1208 if(!iterator.delete_block(false))
1209 return die_ss_("iterator.delete_block(false)", iterator);
1210 delete_from_our_metadata_(our_current_position--);
1212 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1215 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1216 if(!iterator.delete_block(false))
1217 return die_ss_("iterator.delete_block(false)", iterator);
1218 delete_from_our_metadata_(our_current_position--);
1220 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1223 printf("SV[A]P\tnext\n");
1224 if(!iterator.next())
1225 return die_("iterator ended early\n");
1226 our_current_position++;
1228 printf("SVA[P]\tinsert PADDING after\n");
1229 padding->set_length(5);
1230 if(!iterator.insert_block_after(padding, false))
1231 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1232 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1235 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1238 printf("SVAP[P]\tprev\n");
1239 if(!iterator.prev())
1240 return die_("iterator ended early\n");
1241 our_current_position--;
1243 printf("SVA[P]P\tprev\n");
1244 if(!iterator.prev())
1245 return die_("iterator ended early\n");
1246 our_current_position--;
1248 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1249 if(!app->set_data(data, 32, true))
1250 return die_("setting APPLICATION data");
1251 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1252 return die_("copying object");
1253 if(!iterator.set_block(app, true))
1254 return die_ss_("iterator.set_block(app, true)", iterator);
1256 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1259 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1260 if(!app->set_data(data, 60, true))
1261 return die_("setting APPLICATION data");
1262 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1263 return die_("copying object");
1264 if(!iterator.set_block(app, true))
1265 return die_ss_("iterator.set_block(app, true)", iterator);
1267 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1270 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1271 if(!app->set_data(data, 87, true))
1272 return die_("setting APPLICATION data");
1273 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1274 return die_("copying object");
1275 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1276 if(!iterator.set_block(app, true))
1277 return die_ss_("iterator.set_block(app, true)", iterator);
1279 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1282 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1283 if(!app->set_data(data, 91, true))
1284 return die_("setting APPLICATION data");
1285 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1286 return die_("copying object");
1287 delete_from_our_metadata_(our_current_position+1);
1288 if(!iterator.set_block(app, true))
1289 return die_ss_("iterator.set_block(app, true)", iterator);
1291 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1294 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1295 if(!app->set_data(data, 100, true))
1296 return die_("setting APPLICATION data");
1297 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1298 return die_("copying object");
1299 delete_from_our_metadata_(our_current_position+1);
1300 our_metadata_.blocks[our_current_position]->set_is_last(true);
1301 if(!iterator.set_block(app, true))
1302 return die_ss_("iterator.set_block(app, true)", iterator);
1304 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1307 printf("SV[A]\tset PADDING (equal size)\n");
1308 padding->set_length(app->get_length());
1309 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1310 return die_("copying object");
1311 if(!iterator.set_block(padding, true))
1312 return die_ss_("iterator.set_block(padding, true)", iterator);
1314 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1317 printf("SV[P]\tinsert PADDING after\n");
1318 if(!iterator.insert_block_after(padding, false))
1319 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1320 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1323 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1326 printf("SVP[P]\tinsert PADDING after\n");
1327 padding->set_length(5);
1328 if(!iterator.insert_block_after(padding, false))
1329 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1330 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1333 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1336 printf("SVPP[P]\tprev\n");
1337 if(!iterator.prev())
1338 return die_("iterator ended early\n");
1339 our_current_position--;
1341 printf("SVP[P]P\tprev\n");
1342 if(!iterator.prev())
1343 return die_("iterator ended early\n");
1344 our_current_position--;
1346 printf("SV[P]PP\tprev\n");
1347 if(!iterator.prev())
1348 return die_("iterator ended early\n");
1349 our_current_position--;
1351 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1352 if(!app->set_data(data, 101, true))
1353 return die_("setting APPLICATION data");
1354 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1355 return die_("copying object");
1356 if(!iterator.insert_block_after(app, true))
1357 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1359 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1362 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1363 if(!iterator.delete_block(false))
1364 return die_ss_("iterator.delete_block(false)", iterator);
1365 delete_from_our_metadata_(our_current_position--);
1367 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1370 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1371 if(!app->set_data(data, 97, true))
1372 return die_("setting APPLICATION data");
1373 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1374 return die_("copying object");
1375 if(!iterator.insert_block_after(app, true))
1376 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1378 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1381 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1382 if(!iterator.delete_block(false))
1383 return die_ss_("iterator.delete_block(false)", iterator);
1384 delete_from_our_metadata_(our_current_position--);
1386 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1389 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1390 if(!app->set_data(data, 100, true))
1391 return die_("setting APPLICATION data");
1392 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1393 return die_("copying object");
1394 delete_from_our_metadata_(our_current_position+1);
1395 if(!iterator.insert_block_after(app, true))
1396 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1398 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1401 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1402 if(!iterator.delete_block(false))
1403 return die_ss_("iterator.delete_block(false)", iterator);
1404 delete_from_our_metadata_(our_current_position--);
1406 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1409 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1410 if(!app->set_data(data, 96, true))
1411 return die_("setting APPLICATION data");
1412 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1413 return die_("copying object");
1414 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1415 if(!iterator.insert_block_after(app, true))
1416 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1418 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1421 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1422 if(!iterator.delete_block(false))
1423 return die_ss_("iterator.delete_block(false)", iterator);
1424 delete_from_our_metadata_(our_current_position--);
1426 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1429 printf("S[V]PP\tnext\n");
1430 if(!iterator.next())
1431 return die_("iterator ended early\n");
1432 our_current_position++;
1434 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1435 if(!iterator.delete_block(false))
1436 return die_ss_("iterator.delete_block(false)", iterator);
1437 delete_from_our_metadata_(our_current_position--);
1439 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1442 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1443 if(!app->set_data(data, 1, true))
1444 return die_("setting APPLICATION data");
1445 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1446 return die_("copying object");
1447 delete_from_our_metadata_(our_current_position+1);
1448 if(!iterator.insert_block_after(app, true))
1449 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1451 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1458 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1464 static bool test_level_2_(bool filename_based, bool is_ogg)
1466 FLAC::Metadata::Prototype *block;
1467 FLAC::Metadata::StreamInfo *streaminfo;
1468 FLAC::Metadata::Application *app;
1469 FLAC::Metadata::Padding *padding;
1470 FLAC__byte data[2000];
1471 unsigned our_current_position;
1473 // initialize 'data' to avoid Valgrind errors
1474 memset(data, 0, sizeof(data));
1476 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1478 printf("generate read-only file\n");
1480 if(!generate_file_(/*include_extras=*/false, is_ogg))
1483 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1486 printf("create chain\n");
1487 FLAC::Metadata::Chain chain;
1488 if(!chain.is_valid())
1489 return die_("allocating memory for chain");
1491 printf("read chain\n");
1493 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1494 return die_c_("reading chain", chain.status());
1496 printf("[S]VP\ttest initial metadata\n");
1498 if(!compare_chain_(chain, 0, 0))
1500 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1506 printf("switch file to read-write\n");
1508 if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1511 printf("create iterator\n");
1513 FLAC::Metadata::Iterator iterator;
1514 if(!iterator.is_valid())
1515 return die_("allocating memory for iterator");
1517 our_current_position = 0;
1519 iterator.init(chain);
1521 if(0 == (block = iterator.get_block()))
1522 return die_("getting block from iterator");
1524 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1526 printf("[S]VP\tmodify STREAMINFO, write\n");
1528 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1529 FLAC__ASSERT(0 != streaminfo);
1530 streaminfo->set_sample_rate(32000);
1531 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1532 return die_("copying object");
1535 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1536 return die_c_("during chain.write(false, true)", chain.status());
1537 block = iterator.get_block();
1538 if(!compare_chain_(chain, our_current_position, block))
1541 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1544 printf("[S]VP\tnext\n");
1545 if(!iterator.next())
1546 return die_("iterator ended early\n");
1547 our_current_position++;
1549 printf("S[V]P\tnext\n");
1550 if(!iterator.next())
1551 return die_("iterator ended early\n");
1552 our_current_position++;
1554 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1555 if(0 == (block = iterator.get_block()))
1556 return die_("getting block from iterator");
1557 if(0 == (app = new FLAC::Metadata::Application()))
1558 return die_("new FLAC::Metadata::Application()");
1559 app->set_id((const unsigned char *)"duh");
1560 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1561 return die_("setting APPLICATION data");
1563 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1564 return die_("copying object");
1565 if(!iterator.set_block(app))
1566 return die_c_("iterator.set_block(app)", chain.status());
1568 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1569 return die_c_("during chain.write(false, false)", chain.status());
1570 block = iterator.get_block();
1571 if(!compare_chain_(chain, our_current_position, block))
1574 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1577 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1578 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1579 return die_("copying object");
1580 if(!app->set_data(data, 26, true))
1581 return die_("setting APPLICATION data");
1582 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1583 return die_("copying object");
1584 if(!iterator.set_block(app))
1585 return die_c_("iterator.set_block(app)", chain.status());
1587 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1588 return die_c_("during chain.write(false, false)", chain.status());
1589 block = iterator.get_block();
1590 if(!compare_chain_(chain, our_current_position, block))
1593 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1596 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1597 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1598 return die_("copying object");
1599 if(!app->set_data(data, 28, true))
1600 return die_("setting APPLICATION data");
1601 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1602 return die_("copying object");
1603 if(!iterator.set_block(app))
1604 return die_c_("iterator.set_block(app)", chain.status());
1606 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1607 return die_c_("during chain.write(false, false)", chain.status());
1608 block = iterator.get_block();
1609 if(!compare_chain_(chain, our_current_position, block))
1612 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1615 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1616 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1617 return die_("copying object");
1618 if(!app->set_data(data, 36, true))
1619 return die_("setting APPLICATION data");
1620 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1621 return die_("copying object");
1622 if(!iterator.set_block(app))
1623 return die_c_("iterator.set_block(app)", chain.status());
1625 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1626 return die_c_("during chain.write(false, false)", chain.status());
1627 block = iterator.get_block();
1628 if(!compare_chain_(chain, our_current_position, block))
1631 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1634 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1635 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1636 return die_("copying object");
1637 if(!app->set_data(data, 33, true))
1638 return die_("setting APPLICATION data");
1639 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1640 return die_("copying object");
1641 if(!iterator.set_block(app))
1642 return die_c_("iterator.set_block(app)", chain.status());
1644 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1645 return die_c_("during chain.write(true, false)", chain.status());
1646 block = iterator.get_block();
1647 if(!compare_chain_(chain, our_current_position, block))
1650 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1653 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1654 if(0 == (padding = new FLAC::Metadata::Padding()))
1655 return die_("creating PADDING block");
1656 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1657 return die_("copying object");
1658 if(!app->set_data(data, 29, true))
1659 return die_("setting APPLICATION data");
1660 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1661 return die_("copying object");
1662 padding->set_length(0);
1663 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1664 return die_("internal error");
1665 if(!iterator.set_block(app))
1666 return die_c_("iterator.set_block(app)", chain.status());
1668 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1669 return die_c_("during chain.write(true, false)", chain.status());
1670 block = iterator.get_block();
1671 if(!compare_chain_(chain, our_current_position, block))
1674 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1677 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1678 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1679 return die_("copying object");
1680 if(!app->set_data(data, 16, true))
1681 return die_("setting APPLICATION data");
1682 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1683 return die_("copying object");
1684 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1685 if(!iterator.set_block(app))
1686 return die_c_("iterator.set_block(app)", chain.status());
1688 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1689 return die_c_("during chain.write(true, false)", chain.status());
1690 block = iterator.get_block();
1691 if(!compare_chain_(chain, our_current_position, block))
1694 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1697 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1698 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1699 return die_("copying object");
1700 if(!app->set_data(data, 50, true))
1701 return die_("setting APPLICATION data");
1702 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1703 return die_("copying object");
1704 if(!iterator.set_block(app))
1705 return die_c_("iterator.set_block(app)", chain.status());
1707 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1708 return die_c_("during chain.write(true, false)", chain.status());
1709 block = iterator.get_block();
1710 if(!compare_chain_(chain, our_current_position, block))
1713 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1716 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1717 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1718 return die_("copying object");
1719 if(!app->set_data(data, 56, true))
1720 return die_("setting APPLICATION data");
1721 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1722 return die_("copying object");
1723 add_to_padding_length_(our_current_position+1, -(56 - 50));
1724 if(!iterator.set_block(app))
1725 return die_c_("iterator.set_block(app)", chain.status());
1727 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1728 return die_c_("during chain.write(true, false)", chain.status());
1729 block = iterator.get_block();
1730 if(!compare_chain_(chain, our_current_position, block))
1733 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1736 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1737 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1738 return die_("copying object");
1739 if(!app->set_data(data, 67, true))
1740 return die_("setting APPLICATION data");
1741 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1742 return die_("copying object");
1743 delete_from_our_metadata_(our_current_position+1);
1744 if(!iterator.set_block(app))
1745 return die_c_("iterator.set_block(app)", chain.status());
1747 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1748 return die_c_("during chain.write(true, false)", chain.status());
1749 block = iterator.get_block();
1750 if(!compare_chain_(chain, our_current_position, block))
1753 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1756 printf("SV[A]\tprev\n");
1757 if(!iterator.prev())
1758 return die_("iterator ended early\n");
1759 our_current_position--;
1761 printf("S[V]A\tprev\n");
1762 if(!iterator.prev())
1763 return die_("iterator ended early\n");
1764 our_current_position--;
1766 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1767 if(0 == (padding = new FLAC::Metadata::Padding()))
1768 return die_("creating PADDING block");
1769 padding->set_length(30);
1770 if(!iterator.insert_block_before(padding))
1771 printf("\titerator.insert_block_before() returned false like it should\n");
1773 return die_("iterator.insert_block_before() should have returned false");
1775 printf("[S]VA\tnext\n");
1776 if(!iterator.next())
1777 return die_("iterator ended early\n");
1778 our_current_position++;
1780 printf("S[V]A\tinsert PADDING after\n");
1781 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1782 return die_("copying metadata");
1783 if(!iterator.insert_block_after(padding))
1784 return die_("iterator.insert_block_after(padding)");
1786 block = iterator.get_block();
1787 if(!compare_chain_(chain, our_current_position, block))
1791 printf("SV[P]A\tinsert PADDING before\n");
1792 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1793 return die_("creating PADDING block");
1794 padding->set_length(17);
1795 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1796 return die_("copying metadata");
1797 if(!iterator.insert_block_before(padding))
1798 return die_("iterator.insert_block_before(padding)");
1800 block = iterator.get_block();
1801 if(!compare_chain_(chain, our_current_position, block))
1805 printf("SV[P]PA\tinsert PADDING before\n");
1806 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1807 return die_("creating PADDING block");
1808 padding->set_length(0);
1809 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1810 return die_("copying metadata");
1811 if(!iterator.insert_block_before(padding))
1812 return die_("iterator.insert_block_before(padding)");
1814 block = iterator.get_block();
1815 if(!compare_chain_(chain, our_current_position, block))
1819 printf("SV[P]PPA\tnext\n");
1820 if(!iterator.next())
1821 return die_("iterator ended early\n");
1822 our_current_position++;
1824 printf("SVP[P]PA\tnext\n");
1825 if(!iterator.next())
1826 return die_("iterator ended early\n");
1827 our_current_position++;
1829 printf("SVPP[P]A\tnext\n");
1830 if(!iterator.next())
1831 return die_("iterator ended early\n");
1832 our_current_position++;
1834 printf("SVPPP[A]\tinsert PADDING after\n");
1835 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1836 return die_("creating PADDING block");
1837 padding->set_length(57);
1838 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1839 return die_("copying metadata");
1840 if(!iterator.insert_block_after(padding))
1841 return die_("iterator.insert_block_after(padding)");
1843 block = iterator.get_block();
1844 if(!compare_chain_(chain, our_current_position, block))
1848 printf("SVPPPA[P]\tinsert PADDING before\n");
1849 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1850 return die_("creating PADDING block");
1851 padding->set_length(99);
1852 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1853 return die_("copying metadata");
1854 if(!iterator.insert_block_before(padding))
1855 return die_("iterator.insert_block_before(padding)");
1857 block = iterator.get_block();
1858 if(!compare_chain_(chain, our_current_position, block))
1863 our_current_position = 0;
1865 printf("SVPPPAPP\tmerge padding\n");
1866 chain.merge_padding();
1867 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1868 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1869 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1870 delete_from_our_metadata_(7);
1871 delete_from_our_metadata_(4);
1872 delete_from_our_metadata_(3);
1874 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1875 return die_c_("during chain.write(true, false)", chain.status());
1876 if(!compare_chain_(chain, 0, 0))
1878 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1881 printf("SVPAP\tsort padding\n");
1882 chain.sort_padding();
1883 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1884 delete_from_our_metadata_(2);
1886 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1887 return die_c_("during chain.write(true, false)", chain.status());
1888 if(!compare_chain_(chain, 0, 0))
1890 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1893 printf("create iterator\n");
1895 FLAC::Metadata::Iterator iterator;
1896 if(!iterator.is_valid())
1897 return die_("allocating memory for iterator");
1899 our_current_position = 0;
1901 iterator.init(chain);
1903 printf("[S]VAP\tnext\n");
1904 if(!iterator.next())
1905 return die_("iterator ended early\n");
1906 our_current_position++;
1908 printf("S[V]AP\tnext\n");
1909 if(!iterator.next())
1910 return die_("iterator ended early\n");
1911 our_current_position++;
1913 printf("SV[A]P\tdelete middle block, replace with padding\n");
1914 if(0 == (padding = new FLAC::Metadata::Padding()))
1915 return die_("creating PADDING block");
1916 padding->set_length(71);
1917 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1918 return die_("copying object");
1919 if(!iterator.delete_block(/*replace_with_padding=*/true))
1920 return die_c_("iterator.delete_block(true)", chain.status());
1922 block = iterator.get_block();
1923 if(!compare_chain_(chain, our_current_position, block))
1927 printf("S[V]PP\tnext\n");
1928 if(!iterator.next())
1929 return die_("iterator ended early\n");
1930 our_current_position++;
1932 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1933 delete_from_our_metadata_(our_current_position--);
1934 if(!iterator.delete_block(/*replace_with_padding=*/false))
1935 return die_c_("iterator.delete_block(false)", chain.status());
1937 block = iterator.get_block();
1938 if(!compare_chain_(chain, our_current_position, block))
1942 printf("S[V]P\tnext\n");
1943 if(!iterator.next())
1944 return die_("iterator ended early\n");
1945 our_current_position++;
1947 printf("SV[P]\tdelete last block, replace with padding\n");
1948 if(0 == (padding = new FLAC::Metadata::Padding()))
1949 return die_("creating PADDING block");
1950 padding->set_length(219);
1951 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1952 return die_("copying object");
1953 if(!iterator.delete_block(/*replace_with_padding=*/true))
1954 return die_c_("iterator.delete_block(true)", chain.status());
1956 block = iterator.get_block();
1957 if(!compare_chain_(chain, our_current_position, block))
1961 printf("S[V]P\tnext\n");
1962 if(!iterator.next())
1963 return die_("iterator ended early\n");
1964 our_current_position++;
1966 printf("SV[P]\tdelete last block, don't replace with padding\n");
1967 delete_from_our_metadata_(our_current_position--);
1968 if(!iterator.delete_block(/*replace_with_padding=*/false))
1969 return die_c_("iterator.delete_block(false)", chain.status());
1971 block = iterator.get_block();
1972 if(!compare_chain_(chain, our_current_position, block))
1976 printf("S[V]\tprev\n");
1977 if(!iterator.prev())
1978 return die_("iterator ended early\n");
1979 our_current_position--;
1981 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1982 if(iterator.delete_block(/*replace_with_padding=*/false))
1983 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1985 block = iterator.get_block();
1986 if(!compare_chain_(chain, our_current_position, block))
1990 } // delete iterator
1991 our_current_position = 0;
1993 printf("SV\tmerge padding\n");
1994 chain.merge_padding();
1996 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1997 return die_c_("during chain.write(false, false)", chain.status());
1998 if(!compare_chain_(chain, 0, 0))
2000 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2003 printf("SV\tsort padding\n");
2004 chain.sort_padding();
2006 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
2007 return die_c_("during chain.write(false, false)", chain.status());
2008 if(!compare_chain_(chain, 0, 0))
2010 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2014 if(!remove_file_(flacfilename(is_ogg)))
2020 static bool test_level_2_misc_(bool is_ogg)
2022 ::FLAC__IOCallbacks callbacks;
2024 memset(&callbacks, 0, sizeof(callbacks));
2025 callbacks.read = (::FLAC__IOCallback_Read)fread;
2026 #ifdef FLAC__VALGRIND_TESTING
2027 callbacks.write = chain_write_cb_;
2029 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2031 callbacks.seek = chain_seek_cb_;
2032 callbacks.tell = chain_tell_cb_;
2033 callbacks.eof = chain_eof_cb_;
2035 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2037 printf("generate file\n");
2039 if(!generate_file_(/*include_extras=*/false, is_ogg))
2042 printf("create chain\n");
2043 FLAC::Metadata::Chain chain;
2044 if(!chain.is_valid())
2045 return die_("allocating chain");
2047 printf("read chain (filename-based)\n");
2049 if(!chain.read(flacfilename(is_ogg)))
2050 return die_c_("reading chain", chain.status());
2052 printf("write chain with wrong method Chain::write(with callbacks)\n");
2054 if(chain.write(/*use_padding=*/false, 0, callbacks))
2055 return die_c_("mismatched write should have failed", chain.status());
2056 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2057 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2058 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2061 printf("read chain (filename-based)\n");
2063 if(!chain.read(flacfilename(is_ogg)))
2064 return die_c_("reading chain", chain.status());
2066 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2068 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2069 return die_c_("mismatched write should have failed", chain.status());
2070 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2071 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2072 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2075 printf("read chain (callback-based)\n");
2077 FILE *file = fopen(flacfilename(is_ogg), "rb");
2079 return die_("opening file");
2080 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2082 return die_c_("reading chain", chain.status());
2087 printf("write chain with wrong method write()\n");
2089 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2090 return die_c_("mismatched write should have failed", chain.status());
2091 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2092 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2093 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2096 printf("read chain (callback-based)\n");
2098 FILE *file = fopen(flacfilename(is_ogg), "rb");
2100 return die_("opening file");
2101 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2103 return die_c_("reading chain", chain.status());
2108 printf("testing Chain::check_if_tempfile_needed()... ");
2110 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2111 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2113 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2115 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2117 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2118 return die_c_("mismatched write should have failed", chain.status());
2119 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2120 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2121 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2124 printf("read chain (callback-based)\n");
2126 FILE *file = fopen(flacfilename(is_ogg), "rb");
2128 return die_("opening file");
2129 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2131 return die_c_("reading chain", chain.status());
2136 printf("create iterator\n");
2138 FLAC::Metadata::Iterator iterator;
2139 if(!iterator.is_valid())
2140 return die_("allocating memory for iterator");
2142 iterator.init(chain);
2144 printf("[S]VP\tnext\n");
2145 if(!iterator.next())
2146 return die_("iterator ended early\n");
2148 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2149 if(!iterator.delete_block(/*replace_with_padding=*/false))
2150 return die_c_("block delete failed\n", chain.status());
2152 printf("testing Chain::check_if_tempfile_needed()... ");
2154 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2155 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2157 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2159 printf("write chain with wrong method Chain::write(with callbacks)\n");
2161 if(chain.write(/*use_padding=*/false, 0, callbacks))
2162 return die_c_("mismatched write should have failed", chain.status());
2163 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2164 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2165 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2168 } // delete iterator
2170 if(!remove_file_(flacfilename(is_ogg)))
2176 bool test_metadata_file_manipulation()
2178 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2180 our_metadata_.num_blocks = 0;
2182 if(!test_level_0_())
2185 if(!test_level_1_())
2188 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2190 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2192 if(!test_level_2_misc_(/*is_ogg=*/false))
2195 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2197 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2200 /* when ogg flac write is supported, will have to add this: */
2201 if(!test_level_2_misc_(/*is_ogg=*/true))