1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006,2007 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 <= 1600 /* @@@ [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.mime_type);
604 free(picture.data.picture.description);
605 free(picture.data.picture.data);
610 static bool test_file_(bool is_ogg, bool ignore_metadata)
612 const char *filename = flacfilename(is_ogg);
613 OurFileDecoder decoder(ignore_metadata);
615 mc_our_block_number_ = 0;
616 decoder.error_occurred_ = false;
618 printf("\ttesting '%s'... ", filename);
621 if(!decoder.is_valid())
622 return die_("couldn't allocate decoder instance");
624 decoder.set_md5_checking(true);
625 decoder.set_metadata_respond_all();
626 if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
627 (void)decoder.finish();
628 return die_("initializing decoder\n");
630 if(!decoder.process_until_end_of_stream()) {
631 (void)decoder.finish();
632 return die_("decoding file\n");
635 (void)decoder.finish();
637 if(decoder.error_occurred_)
640 if(mc_our_block_number_ != our_metadata_.num_blocks)
641 return die_("short metadata block count");
647 static bool change_stats_(const char *filename, bool read_only)
649 if(!grabbag__file_change_stats(filename, read_only))
650 return die_("during grabbag__file_change_stats()");
655 static bool remove_file_(const char *filename)
657 while(our_metadata_.num_blocks > 0)
658 delete_from_our_metadata_(0);
660 if(!grabbag__file_remove_file(filename))
661 return die_("removing file");
666 static bool test_level_0_()
668 FLAC::Metadata::StreamInfo streaminfo;
670 printf("\n\n++++++ testing level 0 interface\n");
672 if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
675 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
678 printf("testing FLAC::Metadata::get_streaminfo()... ");
680 if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
681 return die_("during FLAC::Metadata::get_streaminfo()");
683 /* check to see if some basic data matches (c.f. generate_file_()) */
684 if(streaminfo.get_channels() != 1)
685 return die_("mismatch in streaminfo.get_channels()");
686 if(streaminfo.get_bits_per_sample() != 8)
687 return die_("mismatch in streaminfo.get_bits_per_sample()");
688 if(streaminfo.get_sample_rate() != 44100)
689 return die_("mismatch in streaminfo.get_sample_rate()");
690 if(streaminfo.get_min_blocksize() != 576)
691 return die_("mismatch in streaminfo.get_min_blocksize()");
692 if(streaminfo.get_max_blocksize() != 576)
693 return die_("mismatch in streaminfo.get_max_blocksize()");
698 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
700 FLAC::Metadata::VorbisComment *tags = 0;
702 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
703 return die_("during FLAC::Metadata::get_tags()");
705 /* check to see if some basic data matches (c.f. generate_file_()) */
706 if(tags->get_num_comments() != 0)
707 return die_("mismatch in tags->get_num_comments()");
715 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
717 FLAC::Metadata::VorbisComment tags;
719 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
720 return die_("during FLAC::Metadata::get_tags()");
722 /* check to see if some basic data matches (c.f. generate_file_()) */
723 if(tags.get_num_comments() != 0)
724 return die_("mismatch in tags.get_num_comments()");
730 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
732 FLAC::Metadata::CueSheet *cuesheet = 0;
734 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
735 return die_("during FLAC::Metadata::get_cuesheet()");
737 /* check to see if some basic data matches (c.f. generate_file_()) */
738 if(cuesheet->get_lead_in() != 123)
739 return die_("mismatch in cuesheet->get_lead_in()");
747 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
749 FLAC::Metadata::CueSheet cuesheet;
751 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
752 return die_("during FLAC::Metadata::get_cuesheet()");
754 /* check to see if some basic data matches (c.f. generate_file_()) */
755 if(cuesheet.get_lead_in() != 123)
756 return die_("mismatch in cuesheet.get_lead_in()");
762 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
764 FLAC::Metadata::Picture *picture = 0;
766 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)))
767 return die_("during FLAC::Metadata::get_picture()");
769 /* check to see if some basic data matches (c.f. generate_file_()) */
770 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
771 return die_("mismatch in picture->get_type ()");
779 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
781 FLAC::Metadata::Picture picture;
783 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)))
784 return die_("during FLAC::Metadata::get_picture()");
786 /* check to see if some basic data matches (c.f. generate_file_()) */
787 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
788 return die_("mismatch in picture->get_type ()");
793 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
799 static bool test_level_1_()
801 FLAC::Metadata::Prototype *block;
802 FLAC::Metadata::StreamInfo *streaminfo;
803 FLAC::Metadata::Padding *padding;
804 FLAC::Metadata::Application *app;
805 FLAC__byte data[1000];
806 unsigned our_current_position = 0;
808 // initialize 'data' to avoid Valgrind errors
809 memset(data, 0, sizeof(data));
811 printf("\n\n++++++ testing level 1 interface\n");
813 /************************************************************/
815 printf("simple iterator on read-only file\n");
817 if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
820 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
823 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
826 FLAC::Metadata::SimpleIterator iterator;
828 if(!iterator.is_valid())
829 return die_("iterator.is_valid() returned false");
831 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
832 return die_("iterator.init() returned false");
834 printf("is writable = %u\n", (unsigned)iterator.is_writable());
835 if(iterator.is_writable())
836 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
838 printf("iterate forwards\n");
840 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
841 return die_("expected STREAMINFO type from iterator.get_block_type()");
842 if(0 == (block = iterator.get_block()))
843 return die_("getting block 0");
844 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
845 return die_("expected STREAMINFO type");
846 if(block->get_is_last())
847 return die_("expected is_last to be false");
848 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
849 return die_("bad STREAMINFO length");
850 /* check to see if some basic data matches (c.f. generate_file_()) */
851 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
852 FLAC__ASSERT(0 != streaminfo);
853 if(streaminfo->get_channels() != 1)
854 return die_("mismatch in channels");
855 if(streaminfo->get_bits_per_sample() != 8)
856 return die_("mismatch in bits_per_sample");
857 if(streaminfo->get_sample_rate() != 44100)
858 return die_("mismatch in sample_rate");
859 if(streaminfo->get_min_blocksize() != 576)
860 return die_("mismatch in min_blocksize");
861 if(streaminfo->get_max_blocksize() != 576)
862 return die_("mismatch in max_blocksize");
863 // we will delete streaminfo a little later when we're really done with it...
866 return die_("forward iterator ended early");
867 our_current_position++;
870 return die_("forward iterator ended early");
871 our_current_position++;
873 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
874 return die_("expected PADDING type from iterator.get_block_type()");
875 if(0 == (block = iterator.get_block()))
876 return die_("getting block 1");
877 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
878 return die_("expected PADDING type");
879 if(!block->get_is_last())
880 return die_("expected is_last to be true");
881 /* check to see if some basic data matches (c.f. generate_file_()) */
882 if(block->get_length() != 1234)
883 return die_("bad PADDING length");
887 return die_("forward iterator returned true but should have returned false");
889 printf("iterate backwards\n");
891 return die_("reverse iterator ended early");
893 return die_("reverse iterator ended early");
895 return die_("reverse iterator returned true but should have returned false");
897 printf("testing iterator.set_block() on read-only file...\n");
899 if(!iterator.set_block(streaminfo, false))
900 printf("PASSED. iterator.set_block() returned false like it should\n");
902 return die_("iterator.set_block() returned true but shouldn't have");
906 /************************************************************/
908 printf("simple iterator on writable file\n");
910 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
913 printf("creating APPLICATION block\n");
915 if(0 == (app = new FLAC::Metadata::Application()))
916 return die_("new FLAC::Metadata::Application()");
917 app->set_id((const unsigned char *)"duh");
919 printf("creating PADDING block\n");
921 if(0 == (padding = new FLAC::Metadata::Padding()))
922 return die_("new FLAC::Metadata::Padding()");
923 padding->set_length(20);
925 FLAC::Metadata::SimpleIterator iterator;
927 if(!iterator.is_valid())
928 return die_("iterator.is_valid() returned false");
930 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
931 return die_("iterator.init() returned false");
932 our_current_position = 0;
934 printf("is writable = %u\n", (unsigned)iterator.is_writable());
936 printf("[S]VP\ttry to write over STREAMINFO block...\n");
937 if(!iterator.set_block(app, false))
938 printf("\titerator.set_block() returned false like it should\n");
940 return die_("iterator.set_block() returned true but shouldn't have");
942 printf("[S]VP\tnext\n");
944 return die_("iterator ended early\n");
945 our_current_position++;
947 printf("S[V]P\tnext\n");
949 return die_("iterator ended early\n");
950 our_current_position++;
952 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
953 padding->set_length(25);
954 if(!iterator.insert_block_after(padding, false))
955 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
956 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
959 printf("SVP[P]\tprev\n");
961 return die_("iterator ended early\n");
962 our_current_position--;
964 printf("SV[P]P\tprev\n");
966 return die_("iterator ended early\n");
967 our_current_position--;
969 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
970 padding->set_length(30);
971 if(!iterator.insert_block_after(padding, false))
972 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
973 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
976 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
979 printf("SV[P]PP\tprev\n");
981 return die_("iterator ended early\n");
982 our_current_position--;
984 printf("S[V]PPP\tprev\n");
986 return die_("iterator ended early\n");
987 our_current_position--;
989 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
990 if(iterator.delete_block(false))
991 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
993 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
996 printf("[S]VPPP\tnext\n");
998 return die_("iterator ended early\n");
999 our_current_position++;
1001 printf("S[V]PPP\tnext\n");
1002 if(!iterator.next())
1003 return die_("iterator ended early\n");
1004 our_current_position++;
1006 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
1007 if(!iterator.delete_block(true))
1008 return die_ss_("iterator.delete_block(true)", iterator);
1009 our_current_position--;
1011 printf("S[V]PPP\tnext\n");
1012 if(!iterator.next())
1013 return die_("iterator ended early\n");
1014 our_current_position++;
1016 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1017 if(!iterator.delete_block(false))
1018 return die_ss_("iterator.delete_block(false)", iterator);
1019 delete_from_our_metadata_(our_current_position--);
1021 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1024 printf("S[V]PP\tnext\n");
1025 if(!iterator.next())
1026 return die_("iterator ended early\n");
1027 our_current_position++;
1029 printf("SV[P]P\tnext\n");
1030 if(!iterator.next())
1031 return die_("iterator ended early\n");
1032 our_current_position++;
1034 printf("SVP[P]\tdelete (last block), replace with padding\n");
1035 if(!iterator.delete_block(true))
1036 return die_ss_("iterator.delete_block(false)", iterator);
1037 our_current_position--;
1039 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1042 printf("SV[P]P\tnext\n");
1043 if(!iterator.next())
1044 return die_("iterator ended early\n");
1045 our_current_position++;
1047 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1048 if(!iterator.delete_block(false))
1049 return die_ss_("iterator.delete_block(false)", iterator);
1050 delete_from_our_metadata_(our_current_position--);
1052 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1055 printf("SV[P]\tprev\n");
1056 if(!iterator.prev())
1057 return die_("iterator ended early\n");
1058 our_current_position--;
1060 printf("S[V]P\tprev\n");
1061 if(!iterator.prev())
1062 return die_("iterator ended early\n");
1063 our_current_position--;
1065 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1066 FLAC__ASSERT(our_current_position == 0);
1067 block = iterator.get_block();
1068 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1069 FLAC__ASSERT(0 != streaminfo);
1070 streaminfo->set_sample_rate(32000);
1071 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1072 return die_("copying object");
1073 if(!iterator.set_block(block, false))
1074 return die_ss_("iterator.set_block(block, false)", iterator);
1077 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1080 printf("[S]VP\tnext\n");
1081 if(!iterator.next())
1082 return die_("iterator ended early\n");
1083 our_current_position++;
1085 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1086 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1087 if(!iterator.insert_block_after(app, true))
1088 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1089 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1091 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1093 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1096 printf("SV[A]P\tnext\n");
1097 if(!iterator.next())
1098 return die_("iterator ended early\n");
1099 our_current_position++;
1101 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1102 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1103 if(!iterator.set_block(app, true))
1104 return die_ss_("iterator.set_block(app, true)", iterator);
1105 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1107 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1109 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1112 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1113 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1114 if(!app->set_data(data, sizeof(data), true))
1115 return die_("setting APPLICATION data");
1116 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1117 return die_("copying object");
1118 if(!iterator.set_block(app, false))
1119 return die_ss_("iterator.set_block(app, false)", iterator);
1121 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1124 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1125 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1126 if(!app->set_data(data, 12, true))
1127 return die_("setting APPLICATION data");
1128 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1129 return die_("copying object");
1130 if(!iterator.set_block(app, false))
1131 return die_ss_("iterator.set_block(app, false)", iterator);
1133 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1136 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1137 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1138 if(!app->set_data(data, sizeof(data), true))
1139 return die_("setting APPLICATION data");
1140 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1141 return die_("copying object");
1142 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1143 if(!iterator.set_block(app, true))
1144 return die_ss_("iterator.set_block(app, true)", iterator);
1146 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1149 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1150 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1151 if(!app->set_data(data, 23, true))
1152 return die_("setting APPLICATION data");
1153 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1154 return die_("copying object");
1155 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1156 return die_("copying object");
1157 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1158 if(!iterator.set_block(app, true))
1159 return die_ss_("iterator.set_block(app, true)", iterator);
1161 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1164 printf("SVA[A]PP\tnext\n");
1165 if(!iterator.next())
1166 return die_("iterator ended early\n");
1167 our_current_position++;
1169 printf("SVAA[P]P\tnext\n");
1170 if(!iterator.next())
1171 return die_("iterator ended early\n");
1172 our_current_position++;
1174 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1175 padding->set_length(5);
1176 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1177 return die_("copying object");
1178 if(!iterator.set_block(padding, false))
1179 return die_ss_("iterator.set_block(padding, false)", iterator);
1181 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1184 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1185 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1186 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1187 return die_("copying object");
1188 if(!iterator.set_block(app, false))
1189 return die_ss_("iterator.set_block(app, false)", iterator);
1191 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1194 printf("SVAAP[A]\tset PADDING (equal)\n");
1195 padding->set_length(27);
1196 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1197 return die_("copying object");
1198 if(!iterator.set_block(padding, false))
1199 return die_ss_("iterator.set_block(padding, false)", iterator);
1201 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1204 printf("SVAAP[P]\tprev\n");
1205 if(!iterator.prev())
1206 return die_("iterator ended early\n");
1207 our_current_position--;
1209 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1210 if(!iterator.delete_block(false))
1211 return die_ss_("iterator.delete_block(false)", iterator);
1212 delete_from_our_metadata_(our_current_position--);
1214 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1217 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1218 if(!iterator.delete_block(false))
1219 return die_ss_("iterator.delete_block(false)", iterator);
1220 delete_from_our_metadata_(our_current_position--);
1222 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1225 printf("SV[A]P\tnext\n");
1226 if(!iterator.next())
1227 return die_("iterator ended early\n");
1228 our_current_position++;
1230 printf("SVA[P]\tinsert PADDING after\n");
1231 padding->set_length(5);
1232 if(!iterator.insert_block_after(padding, false))
1233 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1234 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1237 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1240 printf("SVAP[P]\tprev\n");
1241 if(!iterator.prev())
1242 return die_("iterator ended early\n");
1243 our_current_position--;
1245 printf("SVA[P]P\tprev\n");
1246 if(!iterator.prev())
1247 return die_("iterator ended early\n");
1248 our_current_position--;
1250 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1251 if(!app->set_data(data, 32, true))
1252 return die_("setting APPLICATION data");
1253 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1254 return die_("copying object");
1255 if(!iterator.set_block(app, true))
1256 return die_ss_("iterator.set_block(app, true)", iterator);
1258 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1261 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1262 if(!app->set_data(data, 60, true))
1263 return die_("setting APPLICATION data");
1264 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1265 return die_("copying object");
1266 if(!iterator.set_block(app, true))
1267 return die_ss_("iterator.set_block(app, true)", iterator);
1269 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1272 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1273 if(!app->set_data(data, 87, true))
1274 return die_("setting APPLICATION data");
1275 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1276 return die_("copying object");
1277 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1278 if(!iterator.set_block(app, true))
1279 return die_ss_("iterator.set_block(app, true)", iterator);
1281 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1284 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1285 if(!app->set_data(data, 91, true))
1286 return die_("setting APPLICATION data");
1287 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1288 return die_("copying object");
1289 delete_from_our_metadata_(our_current_position+1);
1290 if(!iterator.set_block(app, true))
1291 return die_ss_("iterator.set_block(app, true)", iterator);
1293 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1296 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1297 if(!app->set_data(data, 100, true))
1298 return die_("setting APPLICATION data");
1299 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1300 return die_("copying object");
1301 delete_from_our_metadata_(our_current_position+1);
1302 our_metadata_.blocks[our_current_position]->set_is_last(true);
1303 if(!iterator.set_block(app, true))
1304 return die_ss_("iterator.set_block(app, true)", iterator);
1306 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1309 printf("SV[A]\tset PADDING (equal size)\n");
1310 padding->set_length(app->get_length());
1311 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1312 return die_("copying object");
1313 if(!iterator.set_block(padding, true))
1314 return die_ss_("iterator.set_block(padding, true)", iterator);
1316 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1319 printf("SV[P]\tinsert PADDING after\n");
1320 if(!iterator.insert_block_after(padding, false))
1321 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1322 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1325 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1328 printf("SVP[P]\tinsert PADDING after\n");
1329 padding->set_length(5);
1330 if(!iterator.insert_block_after(padding, false))
1331 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1332 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1335 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1338 printf("SVPP[P]\tprev\n");
1339 if(!iterator.prev())
1340 return die_("iterator ended early\n");
1341 our_current_position--;
1343 printf("SVP[P]P\tprev\n");
1344 if(!iterator.prev())
1345 return die_("iterator ended early\n");
1346 our_current_position--;
1348 printf("SV[P]PP\tprev\n");
1349 if(!iterator.prev())
1350 return die_("iterator ended early\n");
1351 our_current_position--;
1353 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1354 if(!app->set_data(data, 101, true))
1355 return die_("setting APPLICATION data");
1356 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1357 return die_("copying object");
1358 if(!iterator.insert_block_after(app, true))
1359 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1361 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1364 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1365 if(!iterator.delete_block(false))
1366 return die_ss_("iterator.delete_block(false)", iterator);
1367 delete_from_our_metadata_(our_current_position--);
1369 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1372 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1373 if(!app->set_data(data, 97, true))
1374 return die_("setting APPLICATION data");
1375 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1376 return die_("copying object");
1377 if(!iterator.insert_block_after(app, true))
1378 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1380 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1383 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1384 if(!iterator.delete_block(false))
1385 return die_ss_("iterator.delete_block(false)", iterator);
1386 delete_from_our_metadata_(our_current_position--);
1388 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1391 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1392 if(!app->set_data(data, 100, true))
1393 return die_("setting APPLICATION data");
1394 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1395 return die_("copying object");
1396 delete_from_our_metadata_(our_current_position+1);
1397 if(!iterator.insert_block_after(app, true))
1398 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1400 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1403 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1404 if(!iterator.delete_block(false))
1405 return die_ss_("iterator.delete_block(false)", iterator);
1406 delete_from_our_metadata_(our_current_position--);
1408 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1411 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1412 if(!app->set_data(data, 96, true))
1413 return die_("setting APPLICATION data");
1414 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1415 return die_("copying object");
1416 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1417 if(!iterator.insert_block_after(app, true))
1418 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1420 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1423 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1424 if(!iterator.delete_block(false))
1425 return die_ss_("iterator.delete_block(false)", iterator);
1426 delete_from_our_metadata_(our_current_position--);
1428 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1431 printf("S[V]PP\tnext\n");
1432 if(!iterator.next())
1433 return die_("iterator ended early\n");
1434 our_current_position++;
1436 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1437 if(!iterator.delete_block(false))
1438 return die_ss_("iterator.delete_block(false)", iterator);
1439 delete_from_our_metadata_(our_current_position--);
1441 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1444 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1445 if(!app->set_data(data, 1, true))
1446 return die_("setting APPLICATION data");
1447 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1448 return die_("copying object");
1449 delete_from_our_metadata_(our_current_position+1);
1450 if(!iterator.insert_block_after(app, true))
1451 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1453 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1460 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1466 static bool test_level_2_(bool filename_based, bool is_ogg)
1468 FLAC::Metadata::Prototype *block;
1469 FLAC::Metadata::StreamInfo *streaminfo;
1470 FLAC::Metadata::Application *app;
1471 FLAC::Metadata::Padding *padding;
1472 FLAC__byte data[2000];
1473 unsigned our_current_position;
1475 // initialize 'data' to avoid Valgrind errors
1476 memset(data, 0, sizeof(data));
1478 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1480 printf("generate read-only file\n");
1482 if(!generate_file_(/*include_extras=*/false, is_ogg))
1485 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1488 printf("create chain\n");
1489 FLAC::Metadata::Chain chain;
1490 if(!chain.is_valid())
1491 return die_("allocating memory for chain");
1493 printf("read chain\n");
1495 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1496 return die_c_("reading chain", chain.status());
1498 printf("[S]VP\ttest initial metadata\n");
1500 if(!compare_chain_(chain, 0, 0))
1502 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1508 printf("switch file to read-write\n");
1510 if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1513 printf("create iterator\n");
1515 FLAC::Metadata::Iterator iterator;
1516 if(!iterator.is_valid())
1517 return die_("allocating memory for iterator");
1519 our_current_position = 0;
1521 iterator.init(chain);
1523 if(0 == (block = iterator.get_block()))
1524 return die_("getting block from iterator");
1526 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1528 printf("[S]VP\tmodify STREAMINFO, write\n");
1530 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1531 FLAC__ASSERT(0 != streaminfo);
1532 streaminfo->set_sample_rate(32000);
1533 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1534 return die_("copying object");
1537 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1538 return die_c_("during chain.write(false, true)", chain.status());
1539 block = iterator.get_block();
1540 if(!compare_chain_(chain, our_current_position, block))
1543 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1546 printf("[S]VP\tnext\n");
1547 if(!iterator.next())
1548 return die_("iterator ended early\n");
1549 our_current_position++;
1551 printf("S[V]P\tnext\n");
1552 if(!iterator.next())
1553 return die_("iterator ended early\n");
1554 our_current_position++;
1556 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1557 if(0 == (block = iterator.get_block()))
1558 return die_("getting block from iterator");
1559 if(0 == (app = new FLAC::Metadata::Application()))
1560 return die_("new FLAC::Metadata::Application()");
1561 app->set_id((const unsigned char *)"duh");
1562 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1563 return die_("setting APPLICATION data");
1565 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1566 return die_("copying object");
1567 if(!iterator.set_block(app))
1568 return die_c_("iterator.set_block(app)", chain.status());
1570 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1571 return die_c_("during chain.write(false, false)", chain.status());
1572 block = iterator.get_block();
1573 if(!compare_chain_(chain, our_current_position, block))
1576 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1579 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1580 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1581 return die_("copying object");
1582 if(!app->set_data(data, 26, true))
1583 return die_("setting APPLICATION data");
1584 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1585 return die_("copying object");
1586 if(!iterator.set_block(app))
1587 return die_c_("iterator.set_block(app)", chain.status());
1589 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1590 return die_c_("during chain.write(false, false)", chain.status());
1591 block = iterator.get_block();
1592 if(!compare_chain_(chain, our_current_position, block))
1595 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1598 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1599 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1600 return die_("copying object");
1601 if(!app->set_data(data, 28, true))
1602 return die_("setting APPLICATION data");
1603 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1604 return die_("copying object");
1605 if(!iterator.set_block(app))
1606 return die_c_("iterator.set_block(app)", chain.status());
1608 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1609 return die_c_("during chain.write(false, false)", chain.status());
1610 block = iterator.get_block();
1611 if(!compare_chain_(chain, our_current_position, block))
1614 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1617 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1618 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1619 return die_("copying object");
1620 if(!app->set_data(data, 36, true))
1621 return die_("setting APPLICATION data");
1622 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1623 return die_("copying object");
1624 if(!iterator.set_block(app))
1625 return die_c_("iterator.set_block(app)", chain.status());
1627 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1628 return die_c_("during chain.write(false, false)", chain.status());
1629 block = iterator.get_block();
1630 if(!compare_chain_(chain, our_current_position, block))
1633 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1636 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1637 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1638 return die_("copying object");
1639 if(!app->set_data(data, 33, true))
1640 return die_("setting APPLICATION data");
1641 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1642 return die_("copying object");
1643 if(!iterator.set_block(app))
1644 return die_c_("iterator.set_block(app)", chain.status());
1646 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1647 return die_c_("during chain.write(true, false)", chain.status());
1648 block = iterator.get_block();
1649 if(!compare_chain_(chain, our_current_position, block))
1652 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1655 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1656 if(0 == (padding = new FLAC::Metadata::Padding()))
1657 return die_("creating PADDING block");
1658 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1659 return die_("copying object");
1660 if(!app->set_data(data, 29, true))
1661 return die_("setting APPLICATION data");
1662 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1663 return die_("copying object");
1664 padding->set_length(0);
1665 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1666 return die_("internal error");
1667 if(!iterator.set_block(app))
1668 return die_c_("iterator.set_block(app)", chain.status());
1670 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1671 return die_c_("during chain.write(true, false)", chain.status());
1672 block = iterator.get_block();
1673 if(!compare_chain_(chain, our_current_position, block))
1676 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1679 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1680 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1681 return die_("copying object");
1682 if(!app->set_data(data, 16, true))
1683 return die_("setting APPLICATION data");
1684 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1685 return die_("copying object");
1686 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1687 if(!iterator.set_block(app))
1688 return die_c_("iterator.set_block(app)", chain.status());
1690 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1691 return die_c_("during chain.write(true, false)", chain.status());
1692 block = iterator.get_block();
1693 if(!compare_chain_(chain, our_current_position, block))
1696 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1699 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1700 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1701 return die_("copying object");
1702 if(!app->set_data(data, 50, true))
1703 return die_("setting APPLICATION data");
1704 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1705 return die_("copying object");
1706 if(!iterator.set_block(app))
1707 return die_c_("iterator.set_block(app)", chain.status());
1709 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1710 return die_c_("during chain.write(true, false)", chain.status());
1711 block = iterator.get_block();
1712 if(!compare_chain_(chain, our_current_position, block))
1715 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1718 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1719 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1720 return die_("copying object");
1721 if(!app->set_data(data, 56, true))
1722 return die_("setting APPLICATION data");
1723 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1724 return die_("copying object");
1725 add_to_padding_length_(our_current_position+1, -(56 - 50));
1726 if(!iterator.set_block(app))
1727 return die_c_("iterator.set_block(app)", chain.status());
1729 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1730 return die_c_("during chain.write(true, false)", chain.status());
1731 block = iterator.get_block();
1732 if(!compare_chain_(chain, our_current_position, block))
1735 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1738 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1739 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1740 return die_("copying object");
1741 if(!app->set_data(data, 67, true))
1742 return die_("setting APPLICATION data");
1743 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1744 return die_("copying object");
1745 delete_from_our_metadata_(our_current_position+1);
1746 if(!iterator.set_block(app))
1747 return die_c_("iterator.set_block(app)", chain.status());
1749 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1750 return die_c_("during chain.write(true, false)", chain.status());
1751 block = iterator.get_block();
1752 if(!compare_chain_(chain, our_current_position, block))
1755 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1758 printf("SV[A]\tprev\n");
1759 if(!iterator.prev())
1760 return die_("iterator ended early\n");
1761 our_current_position--;
1763 printf("S[V]A\tprev\n");
1764 if(!iterator.prev())
1765 return die_("iterator ended early\n");
1766 our_current_position--;
1768 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1769 if(0 == (padding = new FLAC::Metadata::Padding()))
1770 return die_("creating PADDING block");
1771 padding->set_length(30);
1772 if(!iterator.insert_block_before(padding))
1773 printf("\titerator.insert_block_before() returned false like it should\n");
1775 return die_("iterator.insert_block_before() should have returned false");
1777 printf("[S]VA\tnext\n");
1778 if(!iterator.next())
1779 return die_("iterator ended early\n");
1780 our_current_position++;
1782 printf("S[V]A\tinsert PADDING after\n");
1783 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1784 return die_("copying metadata");
1785 if(!iterator.insert_block_after(padding))
1786 return die_("iterator.insert_block_after(padding)");
1788 block = iterator.get_block();
1789 if(!compare_chain_(chain, our_current_position, block))
1793 printf("SV[P]A\tinsert PADDING before\n");
1794 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1795 return die_("creating PADDING block");
1796 padding->set_length(17);
1797 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1798 return die_("copying metadata");
1799 if(!iterator.insert_block_before(padding))
1800 return die_("iterator.insert_block_before(padding)");
1802 block = iterator.get_block();
1803 if(!compare_chain_(chain, our_current_position, block))
1807 printf("SV[P]PA\tinsert PADDING before\n");
1808 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1809 return die_("creating PADDING block");
1810 padding->set_length(0);
1811 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1812 return die_("copying metadata");
1813 if(!iterator.insert_block_before(padding))
1814 return die_("iterator.insert_block_before(padding)");
1816 block = iterator.get_block();
1817 if(!compare_chain_(chain, our_current_position, block))
1821 printf("SV[P]PPA\tnext\n");
1822 if(!iterator.next())
1823 return die_("iterator ended early\n");
1824 our_current_position++;
1826 printf("SVP[P]PA\tnext\n");
1827 if(!iterator.next())
1828 return die_("iterator ended early\n");
1829 our_current_position++;
1831 printf("SVPP[P]A\tnext\n");
1832 if(!iterator.next())
1833 return die_("iterator ended early\n");
1834 our_current_position++;
1836 printf("SVPPP[A]\tinsert PADDING after\n");
1837 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1838 return die_("creating PADDING block");
1839 padding->set_length(57);
1840 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1841 return die_("copying metadata");
1842 if(!iterator.insert_block_after(padding))
1843 return die_("iterator.insert_block_after(padding)");
1845 block = iterator.get_block();
1846 if(!compare_chain_(chain, our_current_position, block))
1850 printf("SVPPPA[P]\tinsert PADDING before\n");
1851 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1852 return die_("creating PADDING block");
1853 padding->set_length(99);
1854 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1855 return die_("copying metadata");
1856 if(!iterator.insert_block_before(padding))
1857 return die_("iterator.insert_block_before(padding)");
1859 block = iterator.get_block();
1860 if(!compare_chain_(chain, our_current_position, block))
1865 our_current_position = 0;
1867 printf("SVPPPAPP\tmerge padding\n");
1868 chain.merge_padding();
1869 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1870 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1871 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1872 delete_from_our_metadata_(7);
1873 delete_from_our_metadata_(4);
1874 delete_from_our_metadata_(3);
1876 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1877 return die_c_("during chain.write(true, false)", chain.status());
1878 if(!compare_chain_(chain, 0, 0))
1880 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1883 printf("SVPAP\tsort padding\n");
1884 chain.sort_padding();
1885 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1886 delete_from_our_metadata_(2);
1888 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1889 return die_c_("during chain.write(true, false)", chain.status());
1890 if(!compare_chain_(chain, 0, 0))
1892 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1895 printf("create iterator\n");
1897 FLAC::Metadata::Iterator iterator;
1898 if(!iterator.is_valid())
1899 return die_("allocating memory for iterator");
1901 our_current_position = 0;
1903 iterator.init(chain);
1905 printf("[S]VAP\tnext\n");
1906 if(!iterator.next())
1907 return die_("iterator ended early\n");
1908 our_current_position++;
1910 printf("S[V]AP\tnext\n");
1911 if(!iterator.next())
1912 return die_("iterator ended early\n");
1913 our_current_position++;
1915 printf("SV[A]P\tdelete middle block, replace with padding\n");
1916 if(0 == (padding = new FLAC::Metadata::Padding()))
1917 return die_("creating PADDING block");
1918 padding->set_length(71);
1919 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1920 return die_("copying object");
1921 if(!iterator.delete_block(/*replace_with_padding=*/true))
1922 return die_c_("iterator.delete_block(true)", chain.status());
1924 block = iterator.get_block();
1925 if(!compare_chain_(chain, our_current_position, block))
1929 printf("S[V]PP\tnext\n");
1930 if(!iterator.next())
1931 return die_("iterator ended early\n");
1932 our_current_position++;
1934 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1935 delete_from_our_metadata_(our_current_position--);
1936 if(!iterator.delete_block(/*replace_with_padding=*/false))
1937 return die_c_("iterator.delete_block(false)", chain.status());
1939 block = iterator.get_block();
1940 if(!compare_chain_(chain, our_current_position, block))
1944 printf("S[V]P\tnext\n");
1945 if(!iterator.next())
1946 return die_("iterator ended early\n");
1947 our_current_position++;
1949 printf("SV[P]\tdelete last block, replace with padding\n");
1950 if(0 == (padding = new FLAC::Metadata::Padding()))
1951 return die_("creating PADDING block");
1952 padding->set_length(219);
1953 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1954 return die_("copying object");
1955 if(!iterator.delete_block(/*replace_with_padding=*/true))
1956 return die_c_("iterator.delete_block(true)", chain.status());
1958 block = iterator.get_block();
1959 if(!compare_chain_(chain, our_current_position, block))
1963 printf("S[V]P\tnext\n");
1964 if(!iterator.next())
1965 return die_("iterator ended early\n");
1966 our_current_position++;
1968 printf("SV[P]\tdelete last block, don't replace with padding\n");
1969 delete_from_our_metadata_(our_current_position--);
1970 if(!iterator.delete_block(/*replace_with_padding=*/false))
1971 return die_c_("iterator.delete_block(false)", chain.status());
1973 block = iterator.get_block();
1974 if(!compare_chain_(chain, our_current_position, block))
1978 printf("S[V]\tprev\n");
1979 if(!iterator.prev())
1980 return die_("iterator ended early\n");
1981 our_current_position--;
1983 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1984 if(iterator.delete_block(/*replace_with_padding=*/false))
1985 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1987 block = iterator.get_block();
1988 if(!compare_chain_(chain, our_current_position, block))
1992 } // delete iterator
1993 our_current_position = 0;
1995 printf("SV\tmerge padding\n");
1996 chain.merge_padding();
1998 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1999 return die_c_("during chain.write(false, false)", chain.status());
2000 if(!compare_chain_(chain, 0, 0))
2002 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2005 printf("SV\tsort padding\n");
2006 chain.sort_padding();
2008 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
2009 return die_c_("during chain.write(false, false)", chain.status());
2010 if(!compare_chain_(chain, 0, 0))
2012 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2016 if(!remove_file_(flacfilename(is_ogg)))
2022 static bool test_level_2_misc_(bool is_ogg)
2024 ::FLAC__IOCallbacks callbacks;
2026 memset(&callbacks, 0, sizeof(callbacks));
2027 callbacks.read = (::FLAC__IOCallback_Read)fread;
2028 #ifdef FLAC__VALGRIND_TESTING
2029 callbacks.write = chain_write_cb_;
2031 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2033 callbacks.seek = chain_seek_cb_;
2034 callbacks.tell = chain_tell_cb_;
2035 callbacks.eof = chain_eof_cb_;
2037 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2039 printf("generate file\n");
2041 if(!generate_file_(/*include_extras=*/false, is_ogg))
2044 printf("create chain\n");
2045 FLAC::Metadata::Chain chain;
2046 if(!chain.is_valid())
2047 return die_("allocating chain");
2049 printf("read chain (filename-based)\n");
2051 if(!chain.read(flacfilename(is_ogg)))
2052 return die_c_("reading chain", chain.status());
2054 printf("write chain with wrong method Chain::write(with callbacks)\n");
2056 if(chain.write(/*use_padding=*/false, 0, callbacks))
2057 return die_c_("mismatched write should have failed", chain.status());
2058 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2059 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2060 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2063 printf("read chain (filename-based)\n");
2065 if(!chain.read(flacfilename(is_ogg)))
2066 return die_c_("reading chain", chain.status());
2068 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2070 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2071 return die_c_("mismatched write should have failed", chain.status());
2072 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2073 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2074 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2077 printf("read chain (callback-based)\n");
2079 FILE *file = fopen(flacfilename(is_ogg), "rb");
2081 return die_("opening file");
2082 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2084 return die_c_("reading chain", chain.status());
2089 printf("write chain with wrong method write()\n");
2091 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2092 return die_c_("mismatched write should have failed", chain.status());
2093 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2094 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2095 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2098 printf("read chain (callback-based)\n");
2100 FILE *file = fopen(flacfilename(is_ogg), "rb");
2102 return die_("opening file");
2103 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2105 return die_c_("reading chain", chain.status());
2110 printf("testing Chain::check_if_tempfile_needed()... ");
2112 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2113 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2115 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2117 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2119 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2120 return die_c_("mismatched write should have failed", chain.status());
2121 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2122 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2123 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2126 printf("read chain (callback-based)\n");
2128 FILE *file = fopen(flacfilename(is_ogg), "rb");
2130 return die_("opening file");
2131 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2133 return die_c_("reading chain", chain.status());
2138 printf("create iterator\n");
2140 FLAC::Metadata::Iterator iterator;
2141 if(!iterator.is_valid())
2142 return die_("allocating memory for iterator");
2144 iterator.init(chain);
2146 printf("[S]VP\tnext\n");
2147 if(!iterator.next())
2148 return die_("iterator ended early\n");
2150 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2151 if(!iterator.delete_block(/*replace_with_padding=*/false))
2152 return die_c_("block delete failed\n", chain.status());
2154 printf("testing Chain::check_if_tempfile_needed()... ");
2156 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2157 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2159 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2161 printf("write chain with wrong method Chain::write(with callbacks)\n");
2163 if(chain.write(/*use_padding=*/false, 0, callbacks))
2164 return die_c_("mismatched write should have failed", chain.status());
2165 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2166 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2167 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2170 } // delete iterator
2172 if(!remove_file_(flacfilename(is_ogg)))
2178 bool test_metadata_file_manipulation()
2180 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2182 our_metadata_.num_blocks = 0;
2184 if(!test_level_0_())
2187 if(!test_level_1_())
2190 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2192 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2194 if(!test_level_2_misc_(/*is_ogg=*/false))
2197 if(FLAC_API_SUPPORTS_OGG_FLAC) {
2198 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2200 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2203 /* when ogg flac write is supported, will have to add this: */
2204 if(!test_level_2_misc_(/*is_ogg=*/true))