1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "file_utils.h"
22 #include "FLAC/assert.h"
23 #include "FLAC++/decoder.h"
24 #include "FLAC++/metadata.h"
26 #include <stdlib.h> /* for malloc() */
27 #include <string.h> /* for memcpy()/memset() */
29 /******************************************************************************
30 The general strategy of these tests (for interface levels 1 and 2) is
31 to create a dummy FLAC file with a known set of initial metadata
32 blocks, then keep a mirror locally of what we expect the metadata to be
33 after each operation. Then testing becomes a simple matter of running
34 a FLAC::Decoder::File over the dummy file after each operation, comparing
35 the decoded metadata to what's in our local copy. If there are any
36 differences in the metadata, or the actual audio data is corrupted, we
37 will catch it while decoding.
38 ******************************************************************************/
40 class OurFileDecoder: public FLAC::Decoder::File {
42 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
44 bool ignore_metadata_;;
47 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
48 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
49 void error_callback(::FLAC__StreamDecoderErrorStatus status);
53 FLAC::Metadata::Prototype *blocks[64];
57 static const char *flacfile_ = "metadata.flac";
59 /* our copy of the metadata in flacfile_ */
60 static OurMetadata our_metadata_;
62 /* the current block number that corresponds to the position of the iterator we are testing */
63 static unsigned mc_our_block_number_ = 0;
65 static bool die_(const char *msg)
67 printf("ERROR: %s\n", msg);
71 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
73 printf("ERROR: %s\n", msg);
74 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
78 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
80 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
81 printf("ERROR: %s\n", msg);
82 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
86 static void *malloc_or_die_(size_t size)
88 void *x = malloc(size);
90 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
96 /* functions for working with our metadata copy */
98 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
101 FLAC::Metadata::Prototype *obj = block;
102 FLAC__ASSERT(position < our_metadata_.num_blocks);
104 if(0 == (obj = FLAC::Metadata::clone(block)))
105 return die_("during FLAC::Metadata::clone()");
107 delete our_metadata_.blocks[position];
108 our_metadata_.blocks[position] = obj;
110 /* set the is_last flags */
111 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
112 our_metadata_.blocks[i]->set_is_last(false);
113 our_metadata_.blocks[i]->set_is_last(true);
118 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
121 FLAC::Metadata::Prototype *obj = block;
123 if(0 == (obj = FLAC::Metadata::clone(block)))
124 return die_("during FLAC::Metadata::clone()");
126 if(position > our_metadata_.num_blocks) {
127 position = our_metadata_.num_blocks;
130 for(i = our_metadata_.num_blocks; i > position; i--)
131 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
133 our_metadata_.blocks[position] = obj;
134 our_metadata_.num_blocks++;
136 /* set the is_last flags */
137 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
138 our_metadata_.blocks[i]->set_is_last(false);
139 our_metadata_.blocks[i]->set_is_last(true);
144 static void delete_from_our_metadata_(unsigned position)
147 FLAC__ASSERT(position < our_metadata_.num_blocks);
148 delete our_metadata_.blocks[position];
149 for(i = position; i < our_metadata_.num_blocks - 1; i++)
150 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
151 our_metadata_.num_blocks--;
153 /* set the is_last flags */
154 if(our_metadata_.num_blocks > 0) {
155 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
156 our_metadata_.blocks[i]->set_is_last(false);
157 our_metadata_.blocks[i]->set_is_last(true);
161 void add_to_padding_length_(unsigned index, int delta)
163 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
164 FLAC__ASSERT(0 != padding);
165 padding->set_length((unsigned)((int)padding->get_length() + delta));
168 /* function for comparing our metadata to a FLAC::Metadata::Chain */
170 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
173 FLAC::Metadata::Iterator iterator;
174 FLAC::Metadata::Prototype *block;
177 printf("\tcomparing chain... ");
180 if(!iterator.is_valid())
181 return die_("allocating memory for iterator");
183 iterator.init(chain);
190 if(0 == (block = iterator.get_block()))
191 return die_("getting block from iterator");
193 if(*block != *our_metadata_.blocks[i])
194 return die_("metadata block mismatch");
197 next_ok = iterator.next();
198 } while(i < our_metadata_.num_blocks && next_ok);
201 return die_("chain has more blocks than expected");
203 if(i < our_metadata_.num_blocks)
204 return die_("short block count in chain");
206 if(0 != current_block) {
207 printf("CURRENT_POSITION... ");
210 if(*current_block != *our_metadata_.blocks[current_position])
211 return die_("metadata block mismatch");
219 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
224 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
225 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
227 printf("content... ");
231 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
234 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
236 /* don't bother checking if we've already hit an error */
240 printf("%d... ", mc_our_block_number_);
243 if(!ignore_metadata_) {
244 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
245 (void)die_("got more metadata blocks than expected");
246 error_occurred_ = true;
249 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
250 (void)die_("metadata block mismatch");
251 error_occurred_ = true;
256 mc_our_block_number_++;
259 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
261 error_occurred_ = true;
262 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
265 static bool generate_file_()
267 ::FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
268 ::FLAC__StreamMetadata *metadata[1];
270 printf("generating FLAC file for test\n");
272 while(our_metadata_.num_blocks > 0)
273 delete_from_our_metadata_(0);
275 streaminfo.is_last = false;
276 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
277 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
278 streaminfo.data.stream_info.min_blocksize = 576;
279 streaminfo.data.stream_info.max_blocksize = 576;
280 streaminfo.data.stream_info.min_framesize = 0;
281 streaminfo.data.stream_info.max_framesize = 0;
282 streaminfo.data.stream_info.sample_rate = 44100;
283 streaminfo.data.stream_info.channels = 1;
284 streaminfo.data.stream_info.bits_per_sample = 8;
285 streaminfo.data.stream_info.total_samples = 0;
286 memset(streaminfo.data.stream_info.md5sum, 0, 16);
289 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
290 vorbiscomment.is_last = false;
291 vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
292 vorbiscomment.length = (4 + vendor_string_length) + 4;
293 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
294 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length);
295 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
296 vorbiscomment.data.vorbis_comment.num_comments = 0;
297 vorbiscomment.data.vorbis_comment.comments = 0;
300 padding.is_last = true;
301 padding.type = ::FLAC__METADATA_TYPE_PADDING;
302 padding.length = 1234;
304 metadata[0] = &padding;
306 FLAC::Metadata::StreamInfo s(&streaminfo);
307 FLAC::Metadata::VorbisComment v(&vorbiscomment);
308 FLAC::Metadata::Padding p(&padding);
310 !insert_to_our_metadata_(&s, 0, /*copy=*/true) ||
311 !insert_to_our_metadata_(&v, 1, /*copy=*/true) ||
312 !insert_to_our_metadata_(&p, 2, /*copy=*/true)
314 return die_("priming our metadata");
316 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
317 return die_("creating the encoded file");
319 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
324 static bool test_file_(const char *filename, bool ignore_metadata)
326 OurFileDecoder decoder(ignore_metadata);
328 FLAC__ASSERT(0 != filename);
330 mc_our_block_number_ = 0;
331 decoder.error_occurred_ = false;
333 printf("\ttesting '%s'... ", filename);
336 if(!decoder.is_valid())
337 return die_("couldn't allocate decoder instance");
339 decoder.set_md5_checking(true);
340 decoder.set_filename(filename);
341 decoder.set_metadata_respond_all();
342 if(decoder.init() != ::FLAC__FILE_DECODER_OK) {
344 return die_("initializing decoder\n");
346 if(!decoder.process_until_end_of_file()) {
348 return die_("decoding file\n");
353 if(decoder.error_occurred_)
356 if(mc_our_block_number_ != our_metadata_.num_blocks)
357 return die_("short metadata block count");
363 static bool change_stats_(const char *filename, bool read_only)
365 if(!file_utils__change_stats(filename, read_only))
366 return die_("during file_utils__change_stats()");
371 static bool remove_file_(const char *filename)
373 while(our_metadata_.num_blocks > 0)
374 delete_from_our_metadata_(0);
376 if(!file_utils__remove_file(filename))
377 return die_("removing file");
382 static bool test_level_0_()
384 FLAC::Metadata::StreamInfo streaminfo;
386 printf("\n\n++++++ testing level 0 interface\n");
388 if(!generate_file_())
391 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
394 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
395 return die_("during FLAC::Metadata::get_streaminfo()");
397 /* check to see if some basic data matches (c.f. generate_file_()) */
398 if(streaminfo.get_channels() != 1)
399 return die_("mismatch in streaminfo.get_channels()");
400 if(streaminfo.get_bits_per_sample() != 8)
401 return die_("mismatch in streaminfo.get_bits_per_sample()");
402 if(streaminfo.get_sample_rate() != 44100)
403 return die_("mismatch in streaminfo.get_sample_rate()");
404 if(streaminfo.get_min_blocksize() != 576)
405 return die_("mismatch in streaminfo.get_min_blocksize()");
406 if(streaminfo.get_max_blocksize() != 576)
407 return die_("mismatch in streaminfo.get_max_blocksize()");
409 if(!remove_file_(flacfile_))
415 static bool test_level_1_()
417 FLAC::Metadata::Prototype *block;
418 FLAC::Metadata::StreamInfo *streaminfo;
419 FLAC::Metadata::Padding *padding;
420 FLAC::Metadata::Application *app;
421 FLAC__byte data[1000];
422 unsigned our_current_position = 0;
424 printf("\n\n++++++ testing level 1 interface\n");
426 /************************************************************/
428 printf("simple iterator on read-only file\n");
430 if(!generate_file_())
433 if(!change_stats_(flacfile_, /*read_only=*/true))
436 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
439 FLAC::Metadata::SimpleIterator iterator;
441 if(!iterator.is_valid())
442 return die_("iterator.is_valid() returned false");
444 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
445 return die_("iterator.init() returned false");
447 printf("is writable = %u\n", (unsigned)iterator.is_writable());
448 if(iterator.is_writable())
449 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
451 printf("iterate forwards\n");
453 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
454 return die_("expected STREAMINFO type from iterator.get_block_type()");
455 if(0 == (block = iterator.get_block()))
456 return die_("getting block 0");
457 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
458 return die_("expected STREAMINFO type");
459 if(block->get_is_last())
460 return die_("expected is_last to be false");
461 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
462 return die_("bad STREAMINFO length");
463 /* check to see if some basic data matches (c.f. generate_file_()) */
464 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
465 FLAC__ASSERT(0 != streaminfo);
466 if(streaminfo->get_channels() != 1)
467 return die_("mismatch in channels");
468 if(streaminfo->get_bits_per_sample() != 8)
469 return die_("mismatch in bits_per_sample");
470 if(streaminfo->get_sample_rate() != 44100)
471 return die_("mismatch in sample_rate");
472 if(streaminfo->get_min_blocksize() != 576)
473 return die_("mismatch in min_blocksize");
474 if(streaminfo->get_max_blocksize() != 576)
475 return die_("mismatch in max_blocksize");
478 return die_("forward iterator ended early");
479 our_current_position++;
482 return die_("forward iterator ended early");
483 our_current_position++;
485 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
486 return die_("expected PADDING type from iterator.get_block_type()");
487 if(0 == (block = iterator.get_block()))
488 return die_("getting block 1");
489 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
490 return die_("expected PADDING type");
491 if(!block->get_is_last())
492 return die_("expected is_last to be true");
493 /* check to see if some basic data matches (c.f. generate_file_()) */
494 if(block->get_length() != 1234)
495 return die_("bad PADDING length");
498 return die_("forward iterator returned true but should have returned false");
500 printf("iterate backwards\n");
502 return die_("reverse iterator ended early");
504 return die_("reverse iterator ended early");
506 return die_("reverse iterator returned true but should have returned false");
508 printf("testing iterator.set_block() on read-only file...\n");
510 if(!iterator.set_block(streaminfo, false))
511 printf("PASSED. iterator.set_block() returned false like it should\n");
513 return die_("iterator.set_block() returned true but shouldn't have");
516 /************************************************************/
518 printf("simple iterator on writable file\n");
520 if(!change_stats_(flacfile_, /*read-only=*/false))
523 printf("creating APPLICATION block\n");
525 if(0 == (app = new FLAC::Metadata::Application()))
526 return die_("new FLAC::Metadata::Application()");
527 app->set_id((const unsigned char *)"duh");
529 printf("creating PADDING block\n");
531 if(0 == (padding = new FLAC::Metadata::Padding()))
532 return die_("new FLAC::Metadata::Padding()");
533 padding->set_length(20);
535 FLAC::Metadata::SimpleIterator iterator;
537 if(!iterator.is_valid())
538 return die_("iterator.is_valid() returned false");
540 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
541 return die_("iterator.init() returned false");
542 our_current_position = 0;
544 printf("is writable = %u\n", (unsigned)iterator.is_writable());
546 printf("[S]VP\ttry to write over STREAMINFO block...\n");
547 if(!iterator.set_block(app, false))
548 printf("\titerator.set_block() returned false like it should\n");
550 return die_("iterator.set_block() returned true but shouldn't have");
552 printf("[S]VP\tnext\n");
554 return die_("iterator ended early\n");
555 our_current_position++;
557 printf("S[V]P\tnext\n");
559 return die_("iterator ended early\n");
560 our_current_position++;
562 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
563 padding->set_length(25);
564 if(!iterator.insert_block_after(padding, false))
565 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
566 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
569 printf("SVP[P]\tprev\n");
571 return die_("iterator ended early\n");
572 our_current_position--;
574 printf("SV[P]P\tprev\n");
576 return die_("iterator ended early\n");
577 our_current_position--;
579 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
580 padding->set_length(30);
581 if(!iterator.insert_block_after(padding, false))
582 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
583 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
586 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
589 printf("SV[P]PP\tprev\n");
591 return die_("iterator ended early\n");
592 our_current_position--;
594 printf("S[V]PPP\tprev\n");
596 return die_("iterator ended early\n");
597 our_current_position--;
599 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
600 if(iterator.delete_block(false))
601 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
603 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
606 printf("[S]VPPP\tnext\n");
608 return die_("iterator ended early\n");
609 our_current_position++;
611 printf("S[V]PPP\tnext\n");
613 return die_("iterator ended early\n");
614 our_current_position++;
616 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
617 if(!iterator.delete_block(true))
618 return die_ss_("iterator.delete_block(true)", iterator);
619 our_current_position--;
621 printf("S[V]PPP\tnext\n");
623 return die_("iterator ended early\n");
624 our_current_position++;
626 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
627 if(!iterator.delete_block(false))
628 return die_ss_("iterator.delete_block(false)", iterator);
629 delete_from_our_metadata_(our_current_position--);
631 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
634 printf("S[V]PP\tnext\n");
636 return die_("iterator ended early\n");
637 our_current_position++;
639 printf("SV[P]P\tnext\n");
641 return die_("iterator ended early\n");
642 our_current_position++;
644 printf("SVP[P]\tdelete (last block), replace with padding\n");
645 if(!iterator.delete_block(true))
646 return die_ss_("iterator.delete_block(false)", iterator);
647 our_current_position--;
649 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
652 printf("SV[P]P\tnext\n");
654 return die_("iterator ended early\n");
655 our_current_position++;
657 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
658 if(!iterator.delete_block(false))
659 return die_ss_("iterator.delete_block(false)", iterator);
660 delete_from_our_metadata_(our_current_position--);
662 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
665 printf("SV[P]\tprev\n");
667 return die_("iterator ended early\n");
668 our_current_position--;
670 printf("S[V]P\tprev\n");
672 return die_("iterator ended early\n");
673 our_current_position--;
675 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
676 FLAC__ASSERT(our_current_position == 0);
677 block = iterator.get_block();
678 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
679 FLAC__ASSERT(0 != streaminfo);
680 streaminfo->set_sample_rate(32000);
681 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
682 return die_("copying object");
683 if(!iterator.set_block(block, false))
684 return die_ss_("iterator.set_block(block, false)", iterator);
687 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
690 printf("[S]VP\tnext\n");
692 return die_("iterator ended early\n");
693 our_current_position++;
695 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
696 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
697 if(!iterator.insert_block_after(app, true))
698 return die_ss_("iterator.insert_block_after(app, true)", iterator);
699 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
701 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
703 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
706 printf("SV[A]P\tnext\n");
708 return die_("iterator ended early\n");
709 our_current_position++;
711 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
712 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
713 if(!iterator.set_block(app, true))
714 return die_ss_("iterator.set_block(app, true)", iterator);
715 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
717 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
719 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
722 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
723 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
724 if(!app->set_data(data, sizeof(data), true))
725 return die_("setting APPLICATION data");
726 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
727 return die_("copying object");
728 if(!iterator.set_block(app, false))
729 return die_ss_("iterator.set_block(app, false)", iterator);
731 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
734 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
735 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
736 if(!app->set_data(data, 12, true))
737 return die_("setting APPLICATION data");
738 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
739 return die_("copying object");
740 if(!iterator.set_block(app, false))
741 return die_ss_("iterator.set_block(app, false)", iterator);
743 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
746 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
747 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
748 if(!app->set_data(data, sizeof(data), true))
749 return die_("setting APPLICATION data");
750 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
751 return die_("copying object");
752 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
753 if(!iterator.set_block(app, true))
754 return die_ss_("iterator.set_block(app, true)", iterator);
756 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
759 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
760 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
761 if(!app->set_data(data, 23, true))
762 return die_("setting APPLICATION data");
763 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
764 return die_("copying object");
765 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
766 return die_("copying object");
767 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
768 if(!iterator.set_block(app, true))
769 return die_ss_("iterator.set_block(app, true)", iterator);
771 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
774 printf("SVA[A]PP\tnext\n");
776 return die_("iterator ended early\n");
777 our_current_position++;
779 printf("SVAA[P]P\tnext\n");
781 return die_("iterator ended early\n");
782 our_current_position++;
784 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
785 padding->set_length(5);
786 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
787 return die_("copying object");
788 if(!iterator.set_block(padding, false))
789 return die_ss_("iterator.set_block(padding, false)", iterator);
791 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
794 printf("SVAAP[P]\tset APPLICATION (grow)\n");
795 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
796 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
797 return die_("copying object");
798 if(!iterator.set_block(app, false))
799 return die_ss_("iterator.set_block(app, false)", iterator);
801 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
804 printf("SVAAP[A]\tset PADDING (equal)\n");
805 padding->set_length(27);
806 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
807 return die_("copying object");
808 if(!iterator.set_block(padding, false))
809 return die_ss_("iterator.set_block(padding, false)", iterator);
811 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
814 printf("SVAAP[P]\tprev\n");
816 return die_("iterator ended early\n");
817 our_current_position--;
819 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
820 if(!iterator.delete_block(false))
821 return die_ss_("iterator.delete_block(false)", iterator);
822 delete_from_our_metadata_(our_current_position--);
824 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
827 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
828 if(!iterator.delete_block(false))
829 return die_ss_("iterator.delete_block(false)", iterator);
830 delete_from_our_metadata_(our_current_position--);
832 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
835 printf("SV[A]P\tnext\n");
837 return die_("iterator ended early\n");
838 our_current_position++;
840 printf("SVA[P]\tinsert PADDING after\n");
841 padding->set_length(5);
842 if(!iterator.insert_block_after(padding, false))
843 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
844 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
847 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
850 printf("SVAP[P]\tprev\n");
852 return die_("iterator ended early\n");
853 our_current_position--;
855 printf("SVA[P]P\tprev\n");
857 return die_("iterator ended early\n");
858 our_current_position--;
860 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
861 if(!app->set_data(data, 32, true))
862 return die_("setting APPLICATION data");
863 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
864 return die_("copying object");
865 if(!iterator.set_block(app, true))
866 return die_ss_("iterator.set_block(app, true)", iterator);
868 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
871 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
872 if(!app->set_data(data, 60, true))
873 return die_("setting APPLICATION data");
874 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
875 return die_("copying object");
876 if(!iterator.set_block(app, true))
877 return die_ss_("iterator.set_block(app, true)", iterator);
879 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
882 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
883 if(!app->set_data(data, 87, true))
884 return die_("setting APPLICATION data");
885 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
886 return die_("copying object");
887 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
888 if(!iterator.set_block(app, true))
889 return die_ss_("iterator.set_block(app, true)", iterator);
891 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
894 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
895 if(!app->set_data(data, 91, true))
896 return die_("setting APPLICATION data");
897 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
898 return die_("copying object");
899 delete_from_our_metadata_(our_current_position+1);
900 if(!iterator.set_block(app, true))
901 return die_ss_("iterator.set_block(app, true)", iterator);
903 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
906 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
907 if(!app->set_data(data, 100, true))
908 return die_("setting APPLICATION data");
909 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
910 return die_("copying object");
911 delete_from_our_metadata_(our_current_position+1);
912 our_metadata_.blocks[our_current_position]->set_is_last(true);
913 if(!iterator.set_block(app, true))
914 return die_ss_("iterator.set_block(app, true)", iterator);
916 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
919 printf("SV[A]\tset PADDING (equal size)\n");
920 padding->set_length(app->get_length());
921 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
922 return die_("copying object");
923 if(!iterator.set_block(padding, true))
924 return die_ss_("iterator.set_block(padding, true)", iterator);
926 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
929 printf("SV[P]\tinsert PADDING after\n");
930 if(!iterator.insert_block_after(padding, false))
931 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
932 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
935 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
938 printf("SVP[P]\tinsert PADDING after\n");
939 padding->set_length(5);
940 if(!iterator.insert_block_after(padding, false))
941 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
942 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
945 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
948 printf("SVPP[P]\tprev\n");
950 return die_("iterator ended early\n");
951 our_current_position--;
953 printf("SVP[P]P\tprev\n");
955 return die_("iterator ended early\n");
956 our_current_position--;
958 printf("SV[P]PP\tprev\n");
960 return die_("iterator ended early\n");
961 our_current_position--;
963 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
964 if(!app->set_data(data, 101, true))
965 return die_("setting APPLICATION data");
966 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
967 return die_("copying object");
968 if(!iterator.insert_block_after(app, true))
969 return die_ss_("iterator.insert_block_after(app, true)", iterator);
971 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
974 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
975 if(!iterator.delete_block(false))
976 return die_ss_("iterator.delete_block(false)", iterator);
977 delete_from_our_metadata_(our_current_position--);
979 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
982 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
983 if(!app->set_data(data, 97, true))
984 return die_("setting APPLICATION data");
985 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
986 return die_("copying object");
987 if(!iterator.insert_block_after(app, true))
988 return die_ss_("iterator.insert_block_after(app, true)", iterator);
990 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
993 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
994 if(!iterator.delete_block(false))
995 return die_ss_("iterator.delete_block(false)", iterator);
996 delete_from_our_metadata_(our_current_position--);
998 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1001 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1002 if(!app->set_data(data, 100, true))
1003 return die_("setting APPLICATION data");
1004 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1005 return die_("copying object");
1006 delete_from_our_metadata_(our_current_position+1);
1007 if(!iterator.insert_block_after(app, true))
1008 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1010 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1013 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1014 if(!iterator.delete_block(false))
1015 return die_ss_("iterator.delete_block(false)", iterator);
1016 delete_from_our_metadata_(our_current_position--);
1018 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1021 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1022 if(!app->set_data(data, 96, true))
1023 return die_("setting APPLICATION data");
1024 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1025 return die_("copying object");
1026 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1027 if(!iterator.insert_block_after(app, true))
1028 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1030 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1033 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1034 if(!iterator.delete_block(false))
1035 return die_ss_("iterator.delete_block(false)", iterator);
1036 delete_from_our_metadata_(our_current_position--);
1038 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1041 printf("S[V]PP\tnext\n");
1042 if(!iterator.next())
1043 return die_("iterator ended early\n");
1044 our_current_position++;
1046 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1047 if(!iterator.delete_block(false))
1048 return die_ss_("iterator.delete_block(false)", iterator);
1049 delete_from_our_metadata_(our_current_position--);
1051 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1054 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1055 if(!app->set_data(data, 1, true))
1056 return die_("setting APPLICATION data");
1057 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1058 return die_("copying object");
1059 delete_from_our_metadata_(our_current_position+1);
1060 if(!iterator.insert_block_after(app, true))
1061 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1063 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1070 if(!remove_file_(flacfile_))
1076 static bool test_level_2_()
1078 FLAC::Metadata::Prototype *block;
1079 FLAC::Metadata::StreamInfo *streaminfo;
1080 FLAC::Metadata::Application *app;
1081 FLAC::Metadata::Padding *padding;
1082 FLAC__byte data[2000];
1083 unsigned our_current_position;
1085 printf("\n\n++++++ testing level 2 interface\n");
1087 printf("generate read-only file\n");
1089 if(!generate_file_())
1092 if(!change_stats_(flacfile_, /*read_only=*/true))
1095 printf("create chain\n");
1096 FLAC::Metadata::Chain chain;
1097 if(!chain.is_valid())
1098 return die_("allocating memory for chain");
1100 printf("read chain\n");
1102 if(!chain.read(flacfile_))
1103 return die_c_("reading chain", chain.status());
1105 printf("[S]VP\ttest initial metadata\n");
1107 if(!compare_chain_(chain, 0, 0))
1109 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1112 printf("switch file to read-write\n");
1114 if(!change_stats_(flacfile_, /*read-only=*/false))
1117 printf("create iterator\n");
1119 FLAC::Metadata::Iterator iterator;
1120 if(!iterator.is_valid())
1121 return die_("allocating memory for iterator");
1123 our_current_position = 0;
1125 iterator.init(chain);
1127 if(0 == (block = iterator.get_block()))
1128 return die_("getting block from iterator");
1130 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1132 printf("[S]VP\tmodify STREAMINFO, write\n");
1134 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1135 FLAC__ASSERT(0 != streaminfo);
1136 streaminfo->set_sample_rate(32000);
1137 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1138 return die_("copying object");
1140 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/true))
1141 return die_c_("during chain.write(false, true)", chain.status());
1142 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1144 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1147 printf("[S]VP\tnext\n");
1148 if(!iterator.next())
1149 return die_("iterator ended early\n");
1150 our_current_position++;
1152 printf("S[V]P\tnext\n");
1153 if(!iterator.next())
1154 return die_("iterator ended early\n");
1155 our_current_position++;
1157 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1158 if(0 == (block = iterator.get_block()))
1159 return die_("getting block from iterator");
1160 if(0 == (app = new FLAC::Metadata::Application()))
1161 return die_("new FLAC::Metadata::Application()");
1162 app->set_id((const unsigned char *)"duh");
1163 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1164 return die_("setting APPLICATION data");
1165 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1166 return die_("copying object");
1167 if(!iterator.set_block(app))
1168 return die_c_("iterator.set_block(app)", chain.status());
1170 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1171 return die_c_("during chain.write(false, false)", chain.status());
1172 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1174 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1177 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1178 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1179 return die_("copying object");
1180 if(!app->set_data(data, 26, true))
1181 return die_("setting APPLICATION data");
1182 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1183 return die_("copying object");
1184 if(!iterator.set_block(app))
1185 return die_c_("iterator.set_block(app)", chain.status());
1187 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1188 return die_c_("during chain.write(false, false)", chain.status());
1189 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1191 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1194 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1195 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1196 return die_("copying object");
1197 if(!app->set_data(data, 28, true))
1198 return die_("setting APPLICATION data");
1199 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1200 return die_("copying object");
1201 if(!iterator.set_block(app))
1202 return die_c_("iterator.set_block(app)", chain.status());
1204 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1205 return die_c_("during chain.write(false, false)", chain.status());
1206 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1208 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1211 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1212 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1213 return die_("copying object");
1214 if(!app->set_data(data, 36, true))
1215 return die_("setting APPLICATION data");
1216 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1217 return die_("copying object");
1218 if(!iterator.set_block(app))
1219 return die_c_("iterator.set_block(app)", chain.status());
1221 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1222 return die_c_("during chain.write(false, false)", chain.status());
1223 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1225 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1228 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1229 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1230 return die_("copying object");
1231 if(!app->set_data(data, 33, true))
1232 return die_("setting APPLICATION data");
1233 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1234 return die_("copying object");
1235 if(!iterator.set_block(app))
1236 return die_c_("iterator.set_block(app)", chain.status());
1238 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1239 return die_c_("during chain.write(true, false)", chain.status());
1240 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1242 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1245 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1246 if(0 == (padding = new FLAC::Metadata::Padding()))
1247 return die_("creating PADDING block");
1248 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1249 return die_("copying object");
1250 if(!app->set_data(data, 29, true))
1251 return die_("setting APPLICATION data");
1252 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1253 return die_("copying object");
1254 padding->set_length(0);
1255 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1256 return die_("internal error");
1257 if(!iterator.set_block(app))
1258 return die_c_("iterator.set_block(app)", chain.status());
1260 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1261 return die_c_("during chain.write(true, false)", chain.status());
1262 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1264 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1267 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1268 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1269 return die_("copying object");
1270 if(!app->set_data(data, 16, true))
1271 return die_("setting APPLICATION data");
1272 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1273 return die_("copying object");
1274 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1275 if(!iterator.set_block(app))
1276 return die_c_("iterator.set_block(app)", chain.status());
1278 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1279 return die_c_("during chain.write(true, false)", chain.status());
1280 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1282 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1285 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1286 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1287 return die_("copying object");
1288 if(!app->set_data(data, 50, true))
1289 return die_("setting APPLICATION data");
1290 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1291 return die_("copying object");
1292 if(!iterator.set_block(app))
1293 return die_c_("iterator.set_block(app)", chain.status());
1295 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1296 return die_c_("during chain.write(true, false)", chain.status());
1297 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1299 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1302 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1303 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1304 return die_("copying object");
1305 if(!app->set_data(data, 56, true))
1306 return die_("setting APPLICATION data");
1307 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1308 return die_("copying object");
1309 add_to_padding_length_(our_current_position+1, -(56 - 50));
1310 if(!iterator.set_block(app))
1311 return die_c_("iterator.set_block(app)", chain.status());
1313 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1314 return die_c_("during chain.write(true, false)", chain.status());
1315 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1317 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1320 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1321 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1322 return die_("copying object");
1323 if(!app->set_data(data, 67, true))
1324 return die_("setting APPLICATION data");
1325 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1326 return die_("copying object");
1327 delete_from_our_metadata_(our_current_position+1);
1328 if(!iterator.set_block(app))
1329 return die_c_("iterator.set_block(app)", chain.status());
1331 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1332 return die_c_("during chain.write(true, false)", chain.status());
1333 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1335 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1338 printf("SV[A]\tprev\n");
1339 if(!iterator.prev())
1340 return die_("iterator ended early\n");
1341 our_current_position--;
1343 printf("S[V]A\tprev\n");
1344 if(!iterator.prev())
1345 return die_("iterator ended early\n");
1346 our_current_position--;
1348 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1349 if(0 == (padding = new FLAC::Metadata::Padding()))
1350 return die_("creating PADDING block");
1351 padding->set_length(30);
1352 if(!iterator.insert_block_before(padding))
1353 printf("\titerator.insert_block_before() returned false like it should\n");
1355 return die_("iterator.insert_block_before() should have returned false");
1357 printf("[S]VA\tnext\n");
1358 if(!iterator.next())
1359 return die_("iterator ended early\n");
1360 our_current_position++;
1362 printf("S[V]A\tinsert PADDING after\n");
1363 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1364 return die_("copying metadata");
1365 if(!iterator.insert_block_after(padding))
1366 return die_("iterator.insert_block_after(padding)");
1368 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1371 printf("SV[P]A\tinsert PADDING before\n");
1372 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1373 return die_("creating PADDING block");
1374 padding->set_length(17);
1375 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1376 return die_("copying metadata");
1377 if(!iterator.insert_block_before(padding))
1378 return die_("iterator.insert_block_before(padding)");
1380 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1383 printf("SV[P]PA\tinsert PADDING before\n");
1384 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1385 return die_("creating PADDING block");
1386 padding->set_length(0);
1387 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1388 return die_("copying metadata");
1389 if(!iterator.insert_block_before(padding))
1390 return die_("iterator.insert_block_before(padding)");
1392 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1395 printf("SV[P]PPA\tnext\n");
1396 if(!iterator.next())
1397 return die_("iterator ended early\n");
1398 our_current_position++;
1400 printf("SVP[P]PA\tnext\n");
1401 if(!iterator.next())
1402 return die_("iterator ended early\n");
1403 our_current_position++;
1405 printf("SVPP[P]A\tnext\n");
1406 if(!iterator.next())
1407 return die_("iterator ended early\n");
1408 our_current_position++;
1410 printf("SVPPP[A]\tinsert PADDING after\n");
1411 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1412 return die_("creating PADDING block");
1413 padding->set_length(57);
1414 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1415 return die_("copying metadata");
1416 if(!iterator.insert_block_after(padding))
1417 return die_("iterator.insert_block_after(padding)");
1419 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1422 printf("SVPPPA[P]\tinsert PADDING before\n");
1423 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1424 return die_("creating PADDING block");
1425 padding->set_length(99);
1426 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1427 return die_("copying metadata");
1428 if(!iterator.insert_block_before(padding))
1429 return die_("iterator.insert_block_before(padding)");
1431 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1435 our_current_position = 0;
1437 printf("SVPPPAPP\tmerge padding\n");
1438 chain.merge_padding();
1439 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1440 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1441 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1442 delete_from_our_metadata_(7);
1443 delete_from_our_metadata_(4);
1444 delete_from_our_metadata_(3);
1446 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1447 return die_c_("during chain.write(true, false)", chain.status());
1448 if(!compare_chain_(chain, 0, 0))
1450 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1453 printf("SVPAP\tsort padding\n");
1454 chain.sort_padding();
1455 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1456 delete_from_our_metadata_(2);
1458 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1459 return die_c_("during chain.write(true, false)", chain.status());
1460 if(!compare_chain_(chain, 0, 0))
1462 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1465 printf("create iterator\n");
1467 FLAC::Metadata::Iterator iterator;
1468 if(!iterator.is_valid())
1469 return die_("allocating memory for iterator");
1471 our_current_position = 0;
1473 iterator.init(chain);
1475 printf("[S]VAP\tnext\n");
1476 if(!iterator.next())
1477 return die_("iterator ended early\n");
1478 our_current_position++;
1480 printf("S[V]AP\tnext\n");
1481 if(!iterator.next())
1482 return die_("iterator ended early\n");
1483 our_current_position++;
1485 printf("SV[A]P\tdelete middle block, replace with padding\n");
1486 if(0 == (padding = new FLAC::Metadata::Padding()))
1487 return die_("creating PADDING block");
1488 padding->set_length(71);
1489 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1490 return die_("copying object");
1491 if(!iterator.delete_block(/*replace_with_padding=*/true))
1492 return die_c_("iterator.delete_block(true)", chain.status());
1494 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1497 printf("S[V]PP\tnext\n");
1498 if(!iterator.next())
1499 return die_("iterator ended early\n");
1500 our_current_position++;
1502 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1503 delete_from_our_metadata_(our_current_position--);
1504 if(!iterator.delete_block(/*replace_with_padding=*/false))
1505 return die_c_("iterator.delete_block(false)", chain.status());
1507 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1510 printf("S[V]P\tnext\n");
1511 if(!iterator.next())
1512 return die_("iterator ended early\n");
1513 our_current_position++;
1515 printf("SV[P]\tdelete last block, replace with padding\n");
1516 if(0 == (padding = new FLAC::Metadata::Padding()))
1517 return die_("creating PADDING block");
1518 padding->set_length(219);
1519 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1520 return die_("copying object");
1521 if(!iterator.delete_block(/*replace_with_padding=*/true))
1522 return die_c_("iterator.delete_block(true)", chain.status());
1524 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1527 printf("S[V]P\tnext\n");
1528 if(!iterator.next())
1529 return die_("iterator ended early\n");
1530 our_current_position++;
1532 printf("SV[P]\tdelete last block, don't replace with padding\n");
1533 delete_from_our_metadata_(our_current_position--);
1534 if(!iterator.delete_block(/*replace_with_padding=*/false))
1535 return die_c_("iterator.delete_block(false)", chain.status());
1537 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1540 printf("S[V]\tprev\n");
1541 if(!iterator.prev())
1542 return die_("iterator ended early\n");
1543 our_current_position--;
1545 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1546 if(iterator.delete_block(/*replace_with_padding=*/false))
1547 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1549 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1553 our_current_position = 0;
1555 printf("SV\tmerge padding\n");
1556 chain.merge_padding();
1558 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1559 return die_c_("during chain.write(false, false)", chain.status());
1560 if(!compare_chain_(chain, 0, 0))
1562 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1565 printf("SV\tsort padding\n");
1566 chain.sort_padding();
1568 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1569 return die_c_("during chain.write(false, false)", chain.status());
1570 if(!compare_chain_(chain, 0, 0))
1572 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1575 if(!remove_file_(flacfile_))
1581 bool test_metadata_file_manipulation()
1583 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
1585 our_metadata_.num_blocks = 0;
1587 if(!test_level_0_())
1590 if(!test_level_1_())
1593 if(!test_level_2_())