1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003 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"
25 #include "share/grabbag.h"
27 #include <stdlib.h> /* for malloc() */
28 #include <string.h> /* for memcpy()/memset() */
30 /******************************************************************************
31 The general strategy of these tests (for interface levels 1 and 2) is
32 to create a dummy FLAC file with a known set of initial metadata
33 blocks, then keep a mirror locally of what we expect the metadata to be
34 after each operation. Then testing becomes a simple matter of running
35 a FLAC::Decoder::File over the dummy file after each operation, comparing
36 the decoded metadata to what's in our local copy. If there are any
37 differences in the metadata, or the actual audio data is corrupted, we
38 will catch it while decoding.
39 ******************************************************************************/
41 class OurFileDecoder: public FLAC::Decoder::File {
43 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
45 bool ignore_metadata_;;
48 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
49 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
50 void error_callback(::FLAC__StreamDecoderErrorStatus status);
54 FLAC::Metadata::Prototype *blocks[64];
58 static const char *flacfile_ = "metadata.flac";
60 /* our copy of the metadata in flacfile_ */
61 static OurMetadata our_metadata_;
63 /* the current block number that corresponds to the position of the iterator we are testing */
64 static unsigned mc_our_block_number_ = 0;
66 static bool die_(const char *msg)
68 printf("ERROR: %s\n", msg);
72 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
74 printf("ERROR: %s\n", msg);
75 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
79 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
81 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
82 printf("ERROR: %s\n", msg);
83 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
87 static void *malloc_or_die_(size_t size)
89 void *x = malloc(size);
91 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
97 /* functions for working with our metadata copy */
99 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
102 FLAC::Metadata::Prototype *obj = block;
103 FLAC__ASSERT(position < our_metadata_.num_blocks);
105 if(0 == (obj = FLAC::Metadata::clone(block)))
106 return die_("during FLAC::Metadata::clone()");
108 delete our_metadata_.blocks[position];
109 our_metadata_.blocks[position] = obj;
111 /* set the is_last flags */
112 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
113 our_metadata_.blocks[i]->set_is_last(false);
114 our_metadata_.blocks[i]->set_is_last(true);
119 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
122 FLAC::Metadata::Prototype *obj = block;
124 if(0 == (obj = FLAC::Metadata::clone(block)))
125 return die_("during FLAC::Metadata::clone()");
127 if(position > our_metadata_.num_blocks) {
128 position = our_metadata_.num_blocks;
131 for(i = our_metadata_.num_blocks; i > position; i--)
132 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
134 our_metadata_.blocks[position] = obj;
135 our_metadata_.num_blocks++;
137 /* set the is_last flags */
138 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
139 our_metadata_.blocks[i]->set_is_last(false);
140 our_metadata_.blocks[i]->set_is_last(true);
145 static void delete_from_our_metadata_(unsigned position)
148 FLAC__ASSERT(position < our_metadata_.num_blocks);
149 delete our_metadata_.blocks[position];
150 for(i = position; i < our_metadata_.num_blocks - 1; i++)
151 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
152 our_metadata_.num_blocks--;
154 /* set the is_last flags */
155 if(our_metadata_.num_blocks > 0) {
156 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
157 our_metadata_.blocks[i]->set_is_last(false);
158 our_metadata_.blocks[i]->set_is_last(true);
162 void add_to_padding_length_(unsigned index, int delta)
164 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
165 FLAC__ASSERT(0 != padding);
166 padding->set_length((unsigned)((int)padding->get_length() + delta));
169 /* function for comparing our metadata to a FLAC::Metadata::Chain */
171 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
174 FLAC::Metadata::Iterator iterator;
177 printf("\tcomparing chain... ");
180 if(!iterator.is_valid())
181 return die_("allocating memory for iterator");
183 iterator.init(chain);
187 FLAC::Metadata::Prototype *block;
192 if(0 == (block = iterator.get_block()))
193 return die_("getting block from iterator");
195 if(*block != *our_metadata_.blocks[i])
196 return die_("metadata block mismatch");
200 next_ok = iterator.next();
201 } while(i < our_metadata_.num_blocks && next_ok);
204 return die_("chain has more blocks than expected");
206 if(i < our_metadata_.num_blocks)
207 return die_("short block count in chain");
209 if(0 != current_block) {
210 printf("CURRENT_POSITION... ");
213 if(*current_block != *our_metadata_.blocks[current_position])
214 return die_("metadata block mismatch");
222 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
227 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
228 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
230 printf("content... ");
234 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
237 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
239 /* don't bother checking if we've already hit an error */
243 printf("%d... ", mc_our_block_number_);
246 if(!ignore_metadata_) {
247 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
248 (void)die_("got more metadata blocks than expected");
249 error_occurred_ = true;
252 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
253 (void)die_("metadata block mismatch");
254 error_occurred_ = true;
259 mc_our_block_number_++;
262 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
264 error_occurred_ = true;
265 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
268 static bool generate_file_()
270 ::FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
271 ::FLAC__StreamMetadata *metadata[1];
273 printf("generating FLAC file for test\n");
275 while(our_metadata_.num_blocks > 0)
276 delete_from_our_metadata_(0);
278 streaminfo.is_last = false;
279 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
280 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
281 streaminfo.data.stream_info.min_blocksize = 576;
282 streaminfo.data.stream_info.max_blocksize = 576;
283 streaminfo.data.stream_info.min_framesize = 0;
284 streaminfo.data.stream_info.max_framesize = 0;
285 streaminfo.data.stream_info.sample_rate = 44100;
286 streaminfo.data.stream_info.channels = 1;
287 streaminfo.data.stream_info.bits_per_sample = 8;
288 streaminfo.data.stream_info.total_samples = 0;
289 memset(streaminfo.data.stream_info.md5sum, 0, 16);
292 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
293 vorbiscomment.is_last = false;
294 vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
295 vorbiscomment.length = (4 + vendor_string_length) + 4;
296 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
297 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length);
298 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
299 vorbiscomment.data.vorbis_comment.num_comments = 0;
300 vorbiscomment.data.vorbis_comment.comments = 0;
303 padding.is_last = true;
304 padding.type = ::FLAC__METADATA_TYPE_PADDING;
305 padding.length = 1234;
307 metadata[0] = &padding;
309 FLAC::Metadata::StreamInfo s(&streaminfo);
310 FLAC::Metadata::VorbisComment v(&vorbiscomment);
311 FLAC::Metadata::Padding p(&padding);
313 !insert_to_our_metadata_(&s, 0, /*copy=*/true) ||
314 !insert_to_our_metadata_(&v, 1, /*copy=*/true) ||
315 !insert_to_our_metadata_(&p, 2, /*copy=*/true)
317 return die_("priming our metadata");
319 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
320 return die_("creating the encoded file");
322 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
327 static bool test_file_(const char *filename, bool ignore_metadata)
329 OurFileDecoder decoder(ignore_metadata);
331 FLAC__ASSERT(0 != filename);
333 mc_our_block_number_ = 0;
334 decoder.error_occurred_ = false;
336 printf("\ttesting '%s'... ", filename);
339 if(!decoder.is_valid())
340 return die_("couldn't allocate decoder instance");
342 decoder.set_md5_checking(true);
343 decoder.set_filename(filename);
344 decoder.set_metadata_respond_all();
345 if(decoder.init() != ::FLAC__FILE_DECODER_OK) {
347 return die_("initializing decoder\n");
349 if(!decoder.process_until_end_of_file()) {
351 return die_("decoding file\n");
356 if(decoder.error_occurred_)
359 if(mc_our_block_number_ != our_metadata_.num_blocks)
360 return die_("short metadata block count");
366 static bool change_stats_(const char *filename, bool read_only)
368 if(!grabbag__file_change_stats(filename, read_only))
369 return die_("during grabbag__file_change_stats()");
374 static bool remove_file_(const char *filename)
376 while(our_metadata_.num_blocks > 0)
377 delete_from_our_metadata_(0);
379 if(!grabbag__file_remove_file(filename))
380 return die_("removing file");
385 static bool test_level_0_()
387 FLAC::Metadata::StreamInfo streaminfo;
389 printf("\n\n++++++ testing level 0 interface\n");
391 if(!generate_file_())
394 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
397 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
398 return die_("during FLAC::Metadata::get_streaminfo()");
400 /* check to see if some basic data matches (c.f. generate_file_()) */
401 if(streaminfo.get_channels() != 1)
402 return die_("mismatch in streaminfo.get_channels()");
403 if(streaminfo.get_bits_per_sample() != 8)
404 return die_("mismatch in streaminfo.get_bits_per_sample()");
405 if(streaminfo.get_sample_rate() != 44100)
406 return die_("mismatch in streaminfo.get_sample_rate()");
407 if(streaminfo.get_min_blocksize() != 576)
408 return die_("mismatch in streaminfo.get_min_blocksize()");
409 if(streaminfo.get_max_blocksize() != 576)
410 return die_("mismatch in streaminfo.get_max_blocksize()");
412 if(!remove_file_(flacfile_))
418 static bool test_level_1_()
420 FLAC::Metadata::Prototype *block;
421 FLAC::Metadata::StreamInfo *streaminfo;
422 FLAC::Metadata::Padding *padding;
423 FLAC::Metadata::Application *app;
424 FLAC__byte data[1000];
425 unsigned our_current_position = 0;
427 // initialize 'data' to avoid Valgrind errors
428 memset(data, 0, sizeof(data));
430 printf("\n\n++++++ testing level 1 interface\n");
432 /************************************************************/
434 printf("simple iterator on read-only file\n");
436 if(!generate_file_())
439 if(!change_stats_(flacfile_, /*read_only=*/true))
442 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
445 FLAC::Metadata::SimpleIterator iterator;
447 if(!iterator.is_valid())
448 return die_("iterator.is_valid() returned false");
450 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
451 return die_("iterator.init() returned false");
453 printf("is writable = %u\n", (unsigned)iterator.is_writable());
454 if(iterator.is_writable())
455 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
457 printf("iterate forwards\n");
459 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
460 return die_("expected STREAMINFO type from iterator.get_block_type()");
461 if(0 == (block = iterator.get_block()))
462 return die_("getting block 0");
463 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
464 return die_("expected STREAMINFO type");
465 if(block->get_is_last())
466 return die_("expected is_last to be false");
467 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
468 return die_("bad STREAMINFO length");
469 /* check to see if some basic data matches (c.f. generate_file_()) */
470 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
471 FLAC__ASSERT(0 != streaminfo);
472 if(streaminfo->get_channels() != 1)
473 return die_("mismatch in channels");
474 if(streaminfo->get_bits_per_sample() != 8)
475 return die_("mismatch in bits_per_sample");
476 if(streaminfo->get_sample_rate() != 44100)
477 return die_("mismatch in sample_rate");
478 if(streaminfo->get_min_blocksize() != 576)
479 return die_("mismatch in min_blocksize");
480 if(streaminfo->get_max_blocksize() != 576)
481 return die_("mismatch in max_blocksize");
482 // we will delete streaminfo a little later when we're really done with it...
485 return die_("forward iterator ended early");
486 our_current_position++;
489 return die_("forward iterator ended early");
490 our_current_position++;
492 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
493 return die_("expected PADDING type from iterator.get_block_type()");
494 if(0 == (block = iterator.get_block()))
495 return die_("getting block 1");
496 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
497 return die_("expected PADDING type");
498 if(!block->get_is_last())
499 return die_("expected is_last to be true");
500 /* check to see if some basic data matches (c.f. generate_file_()) */
501 if(block->get_length() != 1234)
502 return die_("bad PADDING length");
506 return die_("forward iterator returned true but should have returned false");
508 printf("iterate backwards\n");
510 return die_("reverse iterator ended early");
512 return die_("reverse iterator ended early");
514 return die_("reverse iterator returned true but should have returned false");
516 printf("testing iterator.set_block() on read-only file...\n");
518 if(!iterator.set_block(streaminfo, false))
519 printf("PASSED. iterator.set_block() returned false like it should\n");
521 return die_("iterator.set_block() returned true but shouldn't have");
525 /************************************************************/
527 printf("simple iterator on writable file\n");
529 if(!change_stats_(flacfile_, /*read-only=*/false))
532 printf("creating APPLICATION block\n");
534 if(0 == (app = new FLAC::Metadata::Application()))
535 return die_("new FLAC::Metadata::Application()");
536 app->set_id((const unsigned char *)"duh");
538 printf("creating PADDING block\n");
540 if(0 == (padding = new FLAC::Metadata::Padding()))
541 return die_("new FLAC::Metadata::Padding()");
542 padding->set_length(20);
544 FLAC::Metadata::SimpleIterator iterator;
546 if(!iterator.is_valid())
547 return die_("iterator.is_valid() returned false");
549 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
550 return die_("iterator.init() returned false");
551 our_current_position = 0;
553 printf("is writable = %u\n", (unsigned)iterator.is_writable());
555 printf("[S]VP\ttry to write over STREAMINFO block...\n");
556 if(!iterator.set_block(app, false))
557 printf("\titerator.set_block() returned false like it should\n");
559 return die_("iterator.set_block() returned true but shouldn't have");
561 printf("[S]VP\tnext\n");
563 return die_("iterator ended early\n");
564 our_current_position++;
566 printf("S[V]P\tnext\n");
568 return die_("iterator ended early\n");
569 our_current_position++;
571 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
572 padding->set_length(25);
573 if(!iterator.insert_block_after(padding, false))
574 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
575 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
578 printf("SVP[P]\tprev\n");
580 return die_("iterator ended early\n");
581 our_current_position--;
583 printf("SV[P]P\tprev\n");
585 return die_("iterator ended early\n");
586 our_current_position--;
588 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
589 padding->set_length(30);
590 if(!iterator.insert_block_after(padding, false))
591 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
592 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
595 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
598 printf("SV[P]PP\tprev\n");
600 return die_("iterator ended early\n");
601 our_current_position--;
603 printf("S[V]PPP\tprev\n");
605 return die_("iterator ended early\n");
606 our_current_position--;
608 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
609 if(iterator.delete_block(false))
610 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
612 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
615 printf("[S]VPPP\tnext\n");
617 return die_("iterator ended early\n");
618 our_current_position++;
620 printf("S[V]PPP\tnext\n");
622 return die_("iterator ended early\n");
623 our_current_position++;
625 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
626 if(!iterator.delete_block(true))
627 return die_ss_("iterator.delete_block(true)", iterator);
628 our_current_position--;
630 printf("S[V]PPP\tnext\n");
632 return die_("iterator ended early\n");
633 our_current_position++;
635 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
636 if(!iterator.delete_block(false))
637 return die_ss_("iterator.delete_block(false)", iterator);
638 delete_from_our_metadata_(our_current_position--);
640 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
643 printf("S[V]PP\tnext\n");
645 return die_("iterator ended early\n");
646 our_current_position++;
648 printf("SV[P]P\tnext\n");
650 return die_("iterator ended early\n");
651 our_current_position++;
653 printf("SVP[P]\tdelete (last block), replace with padding\n");
654 if(!iterator.delete_block(true))
655 return die_ss_("iterator.delete_block(false)", iterator);
656 our_current_position--;
658 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
661 printf("SV[P]P\tnext\n");
663 return die_("iterator ended early\n");
664 our_current_position++;
666 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
667 if(!iterator.delete_block(false))
668 return die_ss_("iterator.delete_block(false)", iterator);
669 delete_from_our_metadata_(our_current_position--);
671 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
674 printf("SV[P]\tprev\n");
676 return die_("iterator ended early\n");
677 our_current_position--;
679 printf("S[V]P\tprev\n");
681 return die_("iterator ended early\n");
682 our_current_position--;
684 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
685 FLAC__ASSERT(our_current_position == 0);
686 block = iterator.get_block();
687 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
688 FLAC__ASSERT(0 != streaminfo);
689 streaminfo->set_sample_rate(32000);
690 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
691 return die_("copying object");
692 if(!iterator.set_block(block, false))
693 return die_ss_("iterator.set_block(block, false)", iterator);
696 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
699 printf("[S]VP\tnext\n");
701 return die_("iterator ended early\n");
702 our_current_position++;
704 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
705 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
706 if(!iterator.insert_block_after(app, true))
707 return die_ss_("iterator.insert_block_after(app, true)", iterator);
708 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
710 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
712 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
715 printf("SV[A]P\tnext\n");
717 return die_("iterator ended early\n");
718 our_current_position++;
720 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
721 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
722 if(!iterator.set_block(app, true))
723 return die_ss_("iterator.set_block(app, true)", iterator);
724 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
726 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
728 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
731 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
732 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
733 if(!app->set_data(data, sizeof(data), true))
734 return die_("setting APPLICATION data");
735 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
736 return die_("copying object");
737 if(!iterator.set_block(app, false))
738 return die_ss_("iterator.set_block(app, false)", iterator);
740 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
743 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
744 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
745 if(!app->set_data(data, 12, true))
746 return die_("setting APPLICATION data");
747 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
748 return die_("copying object");
749 if(!iterator.set_block(app, false))
750 return die_ss_("iterator.set_block(app, false)", iterator);
752 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
755 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
756 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
757 if(!app->set_data(data, sizeof(data), true))
758 return die_("setting APPLICATION data");
759 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
760 return die_("copying object");
761 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
762 if(!iterator.set_block(app, true))
763 return die_ss_("iterator.set_block(app, true)", iterator);
765 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
768 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
769 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
770 if(!app->set_data(data, 23, true))
771 return die_("setting APPLICATION data");
772 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
773 return die_("copying object");
774 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
775 return die_("copying object");
776 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
777 if(!iterator.set_block(app, true))
778 return die_ss_("iterator.set_block(app, true)", iterator);
780 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
783 printf("SVA[A]PP\tnext\n");
785 return die_("iterator ended early\n");
786 our_current_position++;
788 printf("SVAA[P]P\tnext\n");
790 return die_("iterator ended early\n");
791 our_current_position++;
793 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
794 padding->set_length(5);
795 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
796 return die_("copying object");
797 if(!iterator.set_block(padding, false))
798 return die_ss_("iterator.set_block(padding, false)", iterator);
800 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
803 printf("SVAAP[P]\tset APPLICATION (grow)\n");
804 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
805 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
806 return die_("copying object");
807 if(!iterator.set_block(app, false))
808 return die_ss_("iterator.set_block(app, false)", iterator);
810 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
813 printf("SVAAP[A]\tset PADDING (equal)\n");
814 padding->set_length(27);
815 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
816 return die_("copying object");
817 if(!iterator.set_block(padding, false))
818 return die_ss_("iterator.set_block(padding, false)", iterator);
820 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
823 printf("SVAAP[P]\tprev\n");
825 return die_("iterator ended early\n");
826 our_current_position--;
828 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
829 if(!iterator.delete_block(false))
830 return die_ss_("iterator.delete_block(false)", iterator);
831 delete_from_our_metadata_(our_current_position--);
833 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
836 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
837 if(!iterator.delete_block(false))
838 return die_ss_("iterator.delete_block(false)", iterator);
839 delete_from_our_metadata_(our_current_position--);
841 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
844 printf("SV[A]P\tnext\n");
846 return die_("iterator ended early\n");
847 our_current_position++;
849 printf("SVA[P]\tinsert PADDING after\n");
850 padding->set_length(5);
851 if(!iterator.insert_block_after(padding, false))
852 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
853 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
856 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
859 printf("SVAP[P]\tprev\n");
861 return die_("iterator ended early\n");
862 our_current_position--;
864 printf("SVA[P]P\tprev\n");
866 return die_("iterator ended early\n");
867 our_current_position--;
869 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
870 if(!app->set_data(data, 32, true))
871 return die_("setting APPLICATION data");
872 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
873 return die_("copying object");
874 if(!iterator.set_block(app, true))
875 return die_ss_("iterator.set_block(app, true)", iterator);
877 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
880 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
881 if(!app->set_data(data, 60, true))
882 return die_("setting APPLICATION data");
883 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
884 return die_("copying object");
885 if(!iterator.set_block(app, true))
886 return die_ss_("iterator.set_block(app, true)", iterator);
888 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
891 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
892 if(!app->set_data(data, 87, true))
893 return die_("setting APPLICATION data");
894 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
895 return die_("copying object");
896 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
897 if(!iterator.set_block(app, true))
898 return die_ss_("iterator.set_block(app, true)", iterator);
900 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
903 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
904 if(!app->set_data(data, 91, true))
905 return die_("setting APPLICATION data");
906 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
907 return die_("copying object");
908 delete_from_our_metadata_(our_current_position+1);
909 if(!iterator.set_block(app, true))
910 return die_ss_("iterator.set_block(app, true)", iterator);
912 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
915 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
916 if(!app->set_data(data, 100, true))
917 return die_("setting APPLICATION data");
918 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
919 return die_("copying object");
920 delete_from_our_metadata_(our_current_position+1);
921 our_metadata_.blocks[our_current_position]->set_is_last(true);
922 if(!iterator.set_block(app, true))
923 return die_ss_("iterator.set_block(app, true)", iterator);
925 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
928 printf("SV[A]\tset PADDING (equal size)\n");
929 padding->set_length(app->get_length());
930 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
931 return die_("copying object");
932 if(!iterator.set_block(padding, true))
933 return die_ss_("iterator.set_block(padding, true)", iterator);
935 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
938 printf("SV[P]\tinsert PADDING after\n");
939 if(!iterator.insert_block_after(padding, false))
940 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
941 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
944 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
947 printf("SVP[P]\tinsert PADDING after\n");
948 padding->set_length(5);
949 if(!iterator.insert_block_after(padding, false))
950 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
951 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
954 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
957 printf("SVPP[P]\tprev\n");
959 return die_("iterator ended early\n");
960 our_current_position--;
962 printf("SVP[P]P\tprev\n");
964 return die_("iterator ended early\n");
965 our_current_position--;
967 printf("SV[P]PP\tprev\n");
969 return die_("iterator ended early\n");
970 our_current_position--;
972 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
973 if(!app->set_data(data, 101, true))
974 return die_("setting APPLICATION data");
975 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
976 return die_("copying object");
977 if(!iterator.insert_block_after(app, true))
978 return die_ss_("iterator.insert_block_after(app, true)", iterator);
980 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
983 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
984 if(!iterator.delete_block(false))
985 return die_ss_("iterator.delete_block(false)", iterator);
986 delete_from_our_metadata_(our_current_position--);
988 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
991 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
992 if(!app->set_data(data, 97, true))
993 return die_("setting APPLICATION data");
994 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
995 return die_("copying object");
996 if(!iterator.insert_block_after(app, true))
997 return die_ss_("iterator.insert_block_after(app, true)", iterator);
999 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1002 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1003 if(!iterator.delete_block(false))
1004 return die_ss_("iterator.delete_block(false)", iterator);
1005 delete_from_our_metadata_(our_current_position--);
1007 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1010 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1011 if(!app->set_data(data, 100, true))
1012 return die_("setting APPLICATION data");
1013 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1014 return die_("copying object");
1015 delete_from_our_metadata_(our_current_position+1);
1016 if(!iterator.insert_block_after(app, true))
1017 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1019 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1022 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1023 if(!iterator.delete_block(false))
1024 return die_ss_("iterator.delete_block(false)", iterator);
1025 delete_from_our_metadata_(our_current_position--);
1027 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1030 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1031 if(!app->set_data(data, 96, true))
1032 return die_("setting APPLICATION data");
1033 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1034 return die_("copying object");
1035 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1036 if(!iterator.insert_block_after(app, true))
1037 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1039 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1042 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1043 if(!iterator.delete_block(false))
1044 return die_ss_("iterator.delete_block(false)", iterator);
1045 delete_from_our_metadata_(our_current_position--);
1047 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1050 printf("S[V]PP\tnext\n");
1051 if(!iterator.next())
1052 return die_("iterator ended early\n");
1053 our_current_position++;
1055 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1056 if(!iterator.delete_block(false))
1057 return die_ss_("iterator.delete_block(false)", iterator);
1058 delete_from_our_metadata_(our_current_position--);
1060 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1063 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1064 if(!app->set_data(data, 1, true))
1065 return die_("setting APPLICATION data");
1066 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1067 return die_("copying object");
1068 delete_from_our_metadata_(our_current_position+1);
1069 if(!iterator.insert_block_after(app, true))
1070 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1072 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1079 if(!remove_file_(flacfile_))
1085 static bool test_level_2_()
1087 FLAC::Metadata::Prototype *block;
1088 FLAC::Metadata::StreamInfo *streaminfo;
1089 FLAC::Metadata::Application *app;
1090 FLAC::Metadata::Padding *padding;
1091 FLAC__byte data[2000];
1092 unsigned our_current_position;
1094 // initialize 'data' to avoid Valgrind errors
1095 memset(data, 0, sizeof(data));
1097 printf("\n\n++++++ testing level 2 interface\n");
1099 printf("generate read-only file\n");
1101 if(!generate_file_())
1104 if(!change_stats_(flacfile_, /*read_only=*/true))
1107 printf("create chain\n");
1108 FLAC::Metadata::Chain chain;
1109 if(!chain.is_valid())
1110 return die_("allocating memory for chain");
1112 printf("read chain\n");
1114 if(!chain.read(flacfile_))
1115 return die_c_("reading chain", chain.status());
1117 printf("[S]VP\ttest initial metadata\n");
1119 if(!compare_chain_(chain, 0, 0))
1121 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1124 printf("switch file to read-write\n");
1126 if(!change_stats_(flacfile_, /*read-only=*/false))
1129 printf("create iterator\n");
1131 FLAC::Metadata::Iterator iterator;
1132 if(!iterator.is_valid())
1133 return die_("allocating memory for iterator");
1135 our_current_position = 0;
1137 iterator.init(chain);
1139 if(0 == (block = iterator.get_block()))
1140 return die_("getting block from iterator");
1142 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1144 printf("[S]VP\tmodify STREAMINFO, write\n");
1146 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1147 FLAC__ASSERT(0 != streaminfo);
1148 streaminfo->set_sample_rate(32000);
1149 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1150 return die_("copying object");
1153 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/true))
1154 return die_c_("during chain.write(false, true)", chain.status());
1155 block = iterator.get_block();
1156 if(!compare_chain_(chain, our_current_position, block))
1159 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1162 printf("[S]VP\tnext\n");
1163 if(!iterator.next())
1164 return die_("iterator ended early\n");
1165 our_current_position++;
1167 printf("S[V]P\tnext\n");
1168 if(!iterator.next())
1169 return die_("iterator ended early\n");
1170 our_current_position++;
1172 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1173 if(0 == (block = iterator.get_block()))
1174 return die_("getting block from iterator");
1175 if(0 == (app = new FLAC::Metadata::Application()))
1176 return die_("new FLAC::Metadata::Application()");
1177 app->set_id((const unsigned char *)"duh");
1178 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1179 return die_("setting APPLICATION data");
1181 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1182 return die_("copying object");
1183 if(!iterator.set_block(app))
1184 return die_c_("iterator.set_block(app)", chain.status());
1186 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1187 return die_c_("during chain.write(false, false)", chain.status());
1188 block = iterator.get_block();
1189 if(!compare_chain_(chain, our_current_position, block))
1192 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1195 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1196 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1197 return die_("copying object");
1198 if(!app->set_data(data, 26, true))
1199 return die_("setting APPLICATION data");
1200 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1201 return die_("copying object");
1202 if(!iterator.set_block(app))
1203 return die_c_("iterator.set_block(app)", chain.status());
1205 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1206 return die_c_("during chain.write(false, false)", chain.status());
1207 block = iterator.get_block();
1208 if(!compare_chain_(chain, our_current_position, block))
1211 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1214 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1215 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1216 return die_("copying object");
1217 if(!app->set_data(data, 28, true))
1218 return die_("setting APPLICATION data");
1219 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1220 return die_("copying object");
1221 if(!iterator.set_block(app))
1222 return die_c_("iterator.set_block(app)", chain.status());
1224 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1225 return die_c_("during chain.write(false, false)", chain.status());
1226 block = iterator.get_block();
1227 if(!compare_chain_(chain, our_current_position, block))
1230 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1233 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1234 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1235 return die_("copying object");
1236 if(!app->set_data(data, 36, true))
1237 return die_("setting APPLICATION data");
1238 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1239 return die_("copying object");
1240 if(!iterator.set_block(app))
1241 return die_c_("iterator.set_block(app)", chain.status());
1243 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1244 return die_c_("during chain.write(false, false)", chain.status());
1245 block = iterator.get_block();
1246 if(!compare_chain_(chain, our_current_position, block))
1249 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1252 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1253 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1254 return die_("copying object");
1255 if(!app->set_data(data, 33, true))
1256 return die_("setting APPLICATION data");
1257 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1258 return die_("copying object");
1259 if(!iterator.set_block(app))
1260 return die_c_("iterator.set_block(app)", chain.status());
1262 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1263 return die_c_("during chain.write(true, false)", chain.status());
1264 block = iterator.get_block();
1265 if(!compare_chain_(chain, our_current_position, block))
1268 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1271 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1272 if(0 == (padding = new FLAC::Metadata::Padding()))
1273 return die_("creating PADDING block");
1274 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1275 return die_("copying object");
1276 if(!app->set_data(data, 29, true))
1277 return die_("setting APPLICATION data");
1278 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1279 return die_("copying object");
1280 padding->set_length(0);
1281 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1282 return die_("internal error");
1283 if(!iterator.set_block(app))
1284 return die_c_("iterator.set_block(app)", chain.status());
1286 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1287 return die_c_("during chain.write(true, false)", chain.status());
1288 block = iterator.get_block();
1289 if(!compare_chain_(chain, our_current_position, block))
1292 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1295 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1296 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1297 return die_("copying object");
1298 if(!app->set_data(data, 16, true))
1299 return die_("setting APPLICATION data");
1300 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1301 return die_("copying object");
1302 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1303 if(!iterator.set_block(app))
1304 return die_c_("iterator.set_block(app)", chain.status());
1306 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1307 return die_c_("during chain.write(true, false)", chain.status());
1308 block = iterator.get_block();
1309 if(!compare_chain_(chain, our_current_position, block))
1312 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1315 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1316 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1317 return die_("copying object");
1318 if(!app->set_data(data, 50, true))
1319 return die_("setting APPLICATION data");
1320 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1321 return die_("copying object");
1322 if(!iterator.set_block(app))
1323 return die_c_("iterator.set_block(app)", chain.status());
1325 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1326 return die_c_("during chain.write(true, false)", chain.status());
1327 block = iterator.get_block();
1328 if(!compare_chain_(chain, our_current_position, block))
1331 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1334 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1335 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1336 return die_("copying object");
1337 if(!app->set_data(data, 56, true))
1338 return die_("setting APPLICATION data");
1339 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1340 return die_("copying object");
1341 add_to_padding_length_(our_current_position+1, -(56 - 50));
1342 if(!iterator.set_block(app))
1343 return die_c_("iterator.set_block(app)", chain.status());
1345 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1346 return die_c_("during chain.write(true, false)", chain.status());
1347 block = iterator.get_block();
1348 if(!compare_chain_(chain, our_current_position, block))
1351 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1354 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1355 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1356 return die_("copying object");
1357 if(!app->set_data(data, 67, true))
1358 return die_("setting APPLICATION data");
1359 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1360 return die_("copying object");
1361 delete_from_our_metadata_(our_current_position+1);
1362 if(!iterator.set_block(app))
1363 return die_c_("iterator.set_block(app)", chain.status());
1365 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1366 return die_c_("during chain.write(true, false)", chain.status());
1367 block = iterator.get_block();
1368 if(!compare_chain_(chain, our_current_position, block))
1371 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1374 printf("SV[A]\tprev\n");
1375 if(!iterator.prev())
1376 return die_("iterator ended early\n");
1377 our_current_position--;
1379 printf("S[V]A\tprev\n");
1380 if(!iterator.prev())
1381 return die_("iterator ended early\n");
1382 our_current_position--;
1384 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1385 if(0 == (padding = new FLAC::Metadata::Padding()))
1386 return die_("creating PADDING block");
1387 padding->set_length(30);
1388 if(!iterator.insert_block_before(padding))
1389 printf("\titerator.insert_block_before() returned false like it should\n");
1391 return die_("iterator.insert_block_before() should have returned false");
1393 printf("[S]VA\tnext\n");
1394 if(!iterator.next())
1395 return die_("iterator ended early\n");
1396 our_current_position++;
1398 printf("S[V]A\tinsert PADDING after\n");
1399 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1400 return die_("copying metadata");
1401 if(!iterator.insert_block_after(padding))
1402 return die_("iterator.insert_block_after(padding)");
1404 block = iterator.get_block();
1405 if(!compare_chain_(chain, our_current_position, block))
1409 printf("SV[P]A\tinsert PADDING before\n");
1410 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1411 return die_("creating PADDING block");
1412 padding->set_length(17);
1413 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1414 return die_("copying metadata");
1415 if(!iterator.insert_block_before(padding))
1416 return die_("iterator.insert_block_before(padding)");
1418 block = iterator.get_block();
1419 if(!compare_chain_(chain, our_current_position, block))
1423 printf("SV[P]PA\tinsert PADDING before\n");
1424 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1425 return die_("creating PADDING block");
1426 padding->set_length(0);
1427 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1428 return die_("copying metadata");
1429 if(!iterator.insert_block_before(padding))
1430 return die_("iterator.insert_block_before(padding)");
1432 block = iterator.get_block();
1433 if(!compare_chain_(chain, our_current_position, block))
1437 printf("SV[P]PPA\tnext\n");
1438 if(!iterator.next())
1439 return die_("iterator ended early\n");
1440 our_current_position++;
1442 printf("SVP[P]PA\tnext\n");
1443 if(!iterator.next())
1444 return die_("iterator ended early\n");
1445 our_current_position++;
1447 printf("SVPP[P]A\tnext\n");
1448 if(!iterator.next())
1449 return die_("iterator ended early\n");
1450 our_current_position++;
1452 printf("SVPPP[A]\tinsert PADDING after\n");
1453 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1454 return die_("creating PADDING block");
1455 padding->set_length(57);
1456 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1457 return die_("copying metadata");
1458 if(!iterator.insert_block_after(padding))
1459 return die_("iterator.insert_block_after(padding)");
1461 block = iterator.get_block();
1462 if(!compare_chain_(chain, our_current_position, block))
1466 printf("SVPPPA[P]\tinsert PADDING before\n");
1467 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1468 return die_("creating PADDING block");
1469 padding->set_length(99);
1470 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1471 return die_("copying metadata");
1472 if(!iterator.insert_block_before(padding))
1473 return die_("iterator.insert_block_before(padding)");
1475 block = iterator.get_block();
1476 if(!compare_chain_(chain, our_current_position, block))
1481 our_current_position = 0;
1483 printf("SVPPPAPP\tmerge padding\n");
1484 chain.merge_padding();
1485 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1486 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1487 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1488 delete_from_our_metadata_(7);
1489 delete_from_our_metadata_(4);
1490 delete_from_our_metadata_(3);
1492 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1493 return die_c_("during chain.write(true, false)", chain.status());
1494 if(!compare_chain_(chain, 0, 0))
1496 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1499 printf("SVPAP\tsort padding\n");
1500 chain.sort_padding();
1501 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1502 delete_from_our_metadata_(2);
1504 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1505 return die_c_("during chain.write(true, false)", chain.status());
1506 if(!compare_chain_(chain, 0, 0))
1508 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1511 printf("create iterator\n");
1513 FLAC::Metadata::Iterator iterator;
1514 if(!iterator.is_valid())
1515 return die_("allocating memory for iterator");
1517 our_current_position = 0;
1519 iterator.init(chain);
1521 printf("[S]VAP\tnext\n");
1522 if(!iterator.next())
1523 return die_("iterator ended early\n");
1524 our_current_position++;
1526 printf("S[V]AP\tnext\n");
1527 if(!iterator.next())
1528 return die_("iterator ended early\n");
1529 our_current_position++;
1531 printf("SV[A]P\tdelete middle block, replace with padding\n");
1532 if(0 == (padding = new FLAC::Metadata::Padding()))
1533 return die_("creating PADDING block");
1534 padding->set_length(71);
1535 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1536 return die_("copying object");
1537 if(!iterator.delete_block(/*replace_with_padding=*/true))
1538 return die_c_("iterator.delete_block(true)", chain.status());
1540 block = iterator.get_block();
1541 if(!compare_chain_(chain, our_current_position, block))
1545 printf("S[V]PP\tnext\n");
1546 if(!iterator.next())
1547 return die_("iterator ended early\n");
1548 our_current_position++;
1550 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1551 delete_from_our_metadata_(our_current_position--);
1552 if(!iterator.delete_block(/*replace_with_padding=*/false))
1553 return die_c_("iterator.delete_block(false)", chain.status());
1555 block = iterator.get_block();
1556 if(!compare_chain_(chain, our_current_position, block))
1560 printf("S[V]P\tnext\n");
1561 if(!iterator.next())
1562 return die_("iterator ended early\n");
1563 our_current_position++;
1565 printf("SV[P]\tdelete last block, replace with padding\n");
1566 if(0 == (padding = new FLAC::Metadata::Padding()))
1567 return die_("creating PADDING block");
1568 padding->set_length(219);
1569 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1570 return die_("copying object");
1571 if(!iterator.delete_block(/*replace_with_padding=*/true))
1572 return die_c_("iterator.delete_block(true)", chain.status());
1574 block = iterator.get_block();
1575 if(!compare_chain_(chain, our_current_position, block))
1579 printf("S[V]P\tnext\n");
1580 if(!iterator.next())
1581 return die_("iterator ended early\n");
1582 our_current_position++;
1584 printf("SV[P]\tdelete last block, don't replace with padding\n");
1585 delete_from_our_metadata_(our_current_position--);
1586 if(!iterator.delete_block(/*replace_with_padding=*/false))
1587 return die_c_("iterator.delete_block(false)", chain.status());
1589 block = iterator.get_block();
1590 if(!compare_chain_(chain, our_current_position, block))
1594 printf("S[V]\tprev\n");
1595 if(!iterator.prev())
1596 return die_("iterator ended early\n");
1597 our_current_position--;
1599 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1600 if(iterator.delete_block(/*replace_with_padding=*/false))
1601 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1603 block = iterator.get_block();
1604 if(!compare_chain_(chain, our_current_position, block))
1609 our_current_position = 0;
1611 printf("SV\tmerge padding\n");
1612 chain.merge_padding();
1614 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1615 return die_c_("during chain.write(false, false)", chain.status());
1616 if(!compare_chain_(chain, 0, 0))
1618 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1621 printf("SV\tsort padding\n");
1622 chain.sort_padding();
1624 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1625 return die_c_("during chain.write(false, false)", chain.status());
1626 if(!compare_chain_(chain, 0, 0))
1628 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1631 if(!remove_file_(flacfile_))
1637 bool test_metadata_file_manipulation()
1639 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
1641 our_metadata_.num_blocks = 0;
1643 if(!test_level_0_())
1646 if(!test_level_1_())
1649 if(!test_level_2_())