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"
25 #include "share/file_utils.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;
175 FLAC::Metadata::Prototype *block;
178 printf("\tcomparing chain... ");
181 if(!iterator.is_valid())
182 return die_("allocating memory for iterator");
184 iterator.init(chain);
191 if(0 == (block = iterator.get_block()))
192 return die_("getting block from iterator");
194 if(*block != *our_metadata_.blocks[i])
195 return die_("metadata block mismatch");
198 next_ok = iterator.next();
199 } while(i < our_metadata_.num_blocks && next_ok);
202 return die_("chain has more blocks than expected");
204 if(i < our_metadata_.num_blocks)
205 return die_("short block count in chain");
207 if(0 != current_block) {
208 printf("CURRENT_POSITION... ");
211 if(*current_block != *our_metadata_.blocks[current_position])
212 return die_("metadata block mismatch");
220 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
225 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
226 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
228 printf("content... ");
232 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
235 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
237 /* don't bother checking if we've already hit an error */
241 printf("%d... ", mc_our_block_number_);
244 if(!ignore_metadata_) {
245 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
246 (void)die_("got more metadata blocks than expected");
247 error_occurred_ = true;
250 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
251 (void)die_("metadata block mismatch");
252 error_occurred_ = true;
257 mc_our_block_number_++;
260 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
262 error_occurred_ = true;
263 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
266 static bool generate_file_()
268 ::FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
269 ::FLAC__StreamMetadata *metadata[1];
271 printf("generating FLAC file for test\n");
273 while(our_metadata_.num_blocks > 0)
274 delete_from_our_metadata_(0);
276 streaminfo.is_last = false;
277 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
278 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
279 streaminfo.data.stream_info.min_blocksize = 576;
280 streaminfo.data.stream_info.max_blocksize = 576;
281 streaminfo.data.stream_info.min_framesize = 0;
282 streaminfo.data.stream_info.max_framesize = 0;
283 streaminfo.data.stream_info.sample_rate = 44100;
284 streaminfo.data.stream_info.channels = 1;
285 streaminfo.data.stream_info.bits_per_sample = 8;
286 streaminfo.data.stream_info.total_samples = 0;
287 memset(streaminfo.data.stream_info.md5sum, 0, 16);
290 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
291 vorbiscomment.is_last = false;
292 vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
293 vorbiscomment.length = (4 + vendor_string_length) + 4;
294 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
295 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length);
296 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
297 vorbiscomment.data.vorbis_comment.num_comments = 0;
298 vorbiscomment.data.vorbis_comment.comments = 0;
301 padding.is_last = true;
302 padding.type = ::FLAC__METADATA_TYPE_PADDING;
303 padding.length = 1234;
305 metadata[0] = &padding;
307 FLAC::Metadata::StreamInfo s(&streaminfo);
308 FLAC::Metadata::VorbisComment v(&vorbiscomment);
309 FLAC::Metadata::Padding p(&padding);
311 !insert_to_our_metadata_(&s, 0, /*copy=*/true) ||
312 !insert_to_our_metadata_(&v, 1, /*copy=*/true) ||
313 !insert_to_our_metadata_(&p, 2, /*copy=*/true)
315 return die_("priming our metadata");
317 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
318 return die_("creating the encoded file");
320 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
325 static bool test_file_(const char *filename, bool ignore_metadata)
327 OurFileDecoder decoder(ignore_metadata);
329 FLAC__ASSERT(0 != filename);
331 mc_our_block_number_ = 0;
332 decoder.error_occurred_ = false;
334 printf("\ttesting '%s'... ", filename);
337 if(!decoder.is_valid())
338 return die_("couldn't allocate decoder instance");
340 decoder.set_md5_checking(true);
341 decoder.set_filename(filename);
342 decoder.set_metadata_respond_all();
343 if(decoder.init() != ::FLAC__FILE_DECODER_OK) {
345 return die_("initializing decoder\n");
347 if(!decoder.process_until_end_of_file()) {
349 return die_("decoding file\n");
354 if(decoder.error_occurred_)
357 if(mc_our_block_number_ != our_metadata_.num_blocks)
358 return die_("short metadata block count");
364 static bool change_stats_(const char *filename, bool read_only)
366 if(!FLAC__file_utils_change_stats(filename, read_only))
367 return die_("during FLAC__file_utils_change_stats()");
372 static bool remove_file_(const char *filename)
374 while(our_metadata_.num_blocks > 0)
375 delete_from_our_metadata_(0);
377 if(!FLAC__file_utils_remove_file(filename))
378 return die_("removing file");
383 static bool test_level_0_()
385 FLAC::Metadata::StreamInfo streaminfo;
387 printf("\n\n++++++ testing level 0 interface\n");
389 if(!generate_file_())
392 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
395 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
396 return die_("during FLAC::Metadata::get_streaminfo()");
398 /* check to see if some basic data matches (c.f. generate_file_()) */
399 if(streaminfo.get_channels() != 1)
400 return die_("mismatch in streaminfo.get_channels()");
401 if(streaminfo.get_bits_per_sample() != 8)
402 return die_("mismatch in streaminfo.get_bits_per_sample()");
403 if(streaminfo.get_sample_rate() != 44100)
404 return die_("mismatch in streaminfo.get_sample_rate()");
405 if(streaminfo.get_min_blocksize() != 576)
406 return die_("mismatch in streaminfo.get_min_blocksize()");
407 if(streaminfo.get_max_blocksize() != 576)
408 return die_("mismatch in streaminfo.get_max_blocksize()");
410 if(!remove_file_(flacfile_))
416 static bool test_level_1_()
418 FLAC::Metadata::Prototype *block;
419 FLAC::Metadata::StreamInfo *streaminfo;
420 FLAC::Metadata::Padding *padding;
421 FLAC::Metadata::Application *app;
422 FLAC__byte data[1000];
423 unsigned our_current_position = 0;
425 printf("\n\n++++++ testing level 1 interface\n");
427 /************************************************************/
429 printf("simple iterator on read-only file\n");
431 if(!generate_file_())
434 if(!change_stats_(flacfile_, /*read_only=*/true))
437 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
440 FLAC::Metadata::SimpleIterator iterator;
442 if(!iterator.is_valid())
443 return die_("iterator.is_valid() returned false");
445 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
446 return die_("iterator.init() returned false");
448 printf("is writable = %u\n", (unsigned)iterator.is_writable());
449 if(iterator.is_writable())
450 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
452 printf("iterate forwards\n");
454 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
455 return die_("expected STREAMINFO type from iterator.get_block_type()");
456 if(0 == (block = iterator.get_block()))
457 return die_("getting block 0");
458 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
459 return die_("expected STREAMINFO type");
460 if(block->get_is_last())
461 return die_("expected is_last to be false");
462 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
463 return die_("bad STREAMINFO length");
464 /* check to see if some basic data matches (c.f. generate_file_()) */
465 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
466 FLAC__ASSERT(0 != streaminfo);
467 if(streaminfo->get_channels() != 1)
468 return die_("mismatch in channels");
469 if(streaminfo->get_bits_per_sample() != 8)
470 return die_("mismatch in bits_per_sample");
471 if(streaminfo->get_sample_rate() != 44100)
472 return die_("mismatch in sample_rate");
473 if(streaminfo->get_min_blocksize() != 576)
474 return die_("mismatch in min_blocksize");
475 if(streaminfo->get_max_blocksize() != 576)
476 return die_("mismatch in max_blocksize");
479 return die_("forward iterator ended early");
480 our_current_position++;
483 return die_("forward iterator ended early");
484 our_current_position++;
486 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
487 return die_("expected PADDING type from iterator.get_block_type()");
488 if(0 == (block = iterator.get_block()))
489 return die_("getting block 1");
490 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
491 return die_("expected PADDING type");
492 if(!block->get_is_last())
493 return die_("expected is_last to be true");
494 /* check to see if some basic data matches (c.f. generate_file_()) */
495 if(block->get_length() != 1234)
496 return die_("bad PADDING length");
499 return die_("forward iterator returned true but should have returned false");
501 printf("iterate backwards\n");
503 return die_("reverse iterator ended early");
505 return die_("reverse iterator ended early");
507 return die_("reverse iterator returned true but should have returned false");
509 printf("testing iterator.set_block() on read-only file...\n");
511 if(!iterator.set_block(streaminfo, false))
512 printf("PASSED. iterator.set_block() returned false like it should\n");
514 return die_("iterator.set_block() returned true but shouldn't have");
517 /************************************************************/
519 printf("simple iterator on writable file\n");
521 if(!change_stats_(flacfile_, /*read-only=*/false))
524 printf("creating APPLICATION block\n");
526 if(0 == (app = new FLAC::Metadata::Application()))
527 return die_("new FLAC::Metadata::Application()");
528 app->set_id((const unsigned char *)"duh");
530 printf("creating PADDING block\n");
532 if(0 == (padding = new FLAC::Metadata::Padding()))
533 return die_("new FLAC::Metadata::Padding()");
534 padding->set_length(20);
536 FLAC::Metadata::SimpleIterator iterator;
538 if(!iterator.is_valid())
539 return die_("iterator.is_valid() returned false");
541 if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
542 return die_("iterator.init() returned false");
543 our_current_position = 0;
545 printf("is writable = %u\n", (unsigned)iterator.is_writable());
547 printf("[S]VP\ttry to write over STREAMINFO block...\n");
548 if(!iterator.set_block(app, false))
549 printf("\titerator.set_block() returned false like it should\n");
551 return die_("iterator.set_block() returned true but shouldn't have");
553 printf("[S]VP\tnext\n");
555 return die_("iterator ended early\n");
556 our_current_position++;
558 printf("S[V]P\tnext\n");
560 return die_("iterator ended early\n");
561 our_current_position++;
563 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
564 padding->set_length(25);
565 if(!iterator.insert_block_after(padding, false))
566 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
567 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
570 printf("SVP[P]\tprev\n");
572 return die_("iterator ended early\n");
573 our_current_position--;
575 printf("SV[P]P\tprev\n");
577 return die_("iterator ended early\n");
578 our_current_position--;
580 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
581 padding->set_length(30);
582 if(!iterator.insert_block_after(padding, false))
583 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
584 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
587 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
590 printf("SV[P]PP\tprev\n");
592 return die_("iterator ended early\n");
593 our_current_position--;
595 printf("S[V]PPP\tprev\n");
597 return die_("iterator ended early\n");
598 our_current_position--;
600 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
601 if(iterator.delete_block(false))
602 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
604 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
607 printf("[S]VPPP\tnext\n");
609 return die_("iterator ended early\n");
610 our_current_position++;
612 printf("S[V]PPP\tnext\n");
614 return die_("iterator ended early\n");
615 our_current_position++;
617 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
618 if(!iterator.delete_block(true))
619 return die_ss_("iterator.delete_block(true)", iterator);
620 our_current_position--;
622 printf("S[V]PPP\tnext\n");
624 return die_("iterator ended early\n");
625 our_current_position++;
627 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
628 if(!iterator.delete_block(false))
629 return die_ss_("iterator.delete_block(false)", iterator);
630 delete_from_our_metadata_(our_current_position--);
632 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
635 printf("S[V]PP\tnext\n");
637 return die_("iterator ended early\n");
638 our_current_position++;
640 printf("SV[P]P\tnext\n");
642 return die_("iterator ended early\n");
643 our_current_position++;
645 printf("SVP[P]\tdelete (last block), replace with padding\n");
646 if(!iterator.delete_block(true))
647 return die_ss_("iterator.delete_block(false)", iterator);
648 our_current_position--;
650 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
653 printf("SV[P]P\tnext\n");
655 return die_("iterator ended early\n");
656 our_current_position++;
658 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
659 if(!iterator.delete_block(false))
660 return die_ss_("iterator.delete_block(false)", iterator);
661 delete_from_our_metadata_(our_current_position--);
663 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
666 printf("SV[P]\tprev\n");
668 return die_("iterator ended early\n");
669 our_current_position--;
671 printf("S[V]P\tprev\n");
673 return die_("iterator ended early\n");
674 our_current_position--;
676 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
677 FLAC__ASSERT(our_current_position == 0);
678 block = iterator.get_block();
679 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
680 FLAC__ASSERT(0 != streaminfo);
681 streaminfo->set_sample_rate(32000);
682 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
683 return die_("copying object");
684 if(!iterator.set_block(block, false))
685 return die_ss_("iterator.set_block(block, false)", iterator);
688 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
691 printf("[S]VP\tnext\n");
693 return die_("iterator ended early\n");
694 our_current_position++;
696 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
697 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
698 if(!iterator.insert_block_after(app, true))
699 return die_ss_("iterator.insert_block_after(app, true)", iterator);
700 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
702 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
704 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
707 printf("SV[A]P\tnext\n");
709 return die_("iterator ended early\n");
710 our_current_position++;
712 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
713 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
714 if(!iterator.set_block(app, true))
715 return die_ss_("iterator.set_block(app, true)", iterator);
716 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
718 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
720 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
723 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
724 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
725 if(!app->set_data(data, sizeof(data), true))
726 return die_("setting APPLICATION data");
727 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
728 return die_("copying object");
729 if(!iterator.set_block(app, false))
730 return die_ss_("iterator.set_block(app, false)", iterator);
732 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
735 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
736 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
737 if(!app->set_data(data, 12, true))
738 return die_("setting APPLICATION data");
739 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
740 return die_("copying object");
741 if(!iterator.set_block(app, false))
742 return die_ss_("iterator.set_block(app, false)", iterator);
744 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
747 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
748 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
749 if(!app->set_data(data, sizeof(data), true))
750 return die_("setting APPLICATION data");
751 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
752 return die_("copying object");
753 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
754 if(!iterator.set_block(app, true))
755 return die_ss_("iterator.set_block(app, true)", iterator);
757 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
760 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
761 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
762 if(!app->set_data(data, 23, true))
763 return die_("setting APPLICATION data");
764 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
765 return die_("copying object");
766 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
767 return die_("copying object");
768 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
769 if(!iterator.set_block(app, true))
770 return die_ss_("iterator.set_block(app, true)", iterator);
772 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
775 printf("SVA[A]PP\tnext\n");
777 return die_("iterator ended early\n");
778 our_current_position++;
780 printf("SVAA[P]P\tnext\n");
782 return die_("iterator ended early\n");
783 our_current_position++;
785 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
786 padding->set_length(5);
787 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
788 return die_("copying object");
789 if(!iterator.set_block(padding, false))
790 return die_ss_("iterator.set_block(padding, false)", iterator);
792 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
795 printf("SVAAP[P]\tset APPLICATION (grow)\n");
796 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
797 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
798 return die_("copying object");
799 if(!iterator.set_block(app, false))
800 return die_ss_("iterator.set_block(app, false)", iterator);
802 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
805 printf("SVAAP[A]\tset PADDING (equal)\n");
806 padding->set_length(27);
807 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
808 return die_("copying object");
809 if(!iterator.set_block(padding, false))
810 return die_ss_("iterator.set_block(padding, false)", iterator);
812 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
815 printf("SVAAP[P]\tprev\n");
817 return die_("iterator ended early\n");
818 our_current_position--;
820 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
821 if(!iterator.delete_block(false))
822 return die_ss_("iterator.delete_block(false)", iterator);
823 delete_from_our_metadata_(our_current_position--);
825 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
828 printf("SVA[A]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("SV[A]P\tnext\n");
838 return die_("iterator ended early\n");
839 our_current_position++;
841 printf("SVA[P]\tinsert PADDING after\n");
842 padding->set_length(5);
843 if(!iterator.insert_block_after(padding, false))
844 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
845 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
848 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
851 printf("SVAP[P]\tprev\n");
853 return die_("iterator ended early\n");
854 our_current_position--;
856 printf("SVA[P]P\tprev\n");
858 return die_("iterator ended early\n");
859 our_current_position--;
861 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
862 if(!app->set_data(data, 32, true))
863 return die_("setting APPLICATION data");
864 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
865 return die_("copying object");
866 if(!iterator.set_block(app, true))
867 return die_ss_("iterator.set_block(app, true)", iterator);
869 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
872 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
873 if(!app->set_data(data, 60, true))
874 return die_("setting APPLICATION data");
875 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
876 return die_("copying object");
877 if(!iterator.set_block(app, true))
878 return die_ss_("iterator.set_block(app, true)", iterator);
880 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
883 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
884 if(!app->set_data(data, 87, true))
885 return die_("setting APPLICATION data");
886 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
887 return die_("copying object");
888 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
889 if(!iterator.set_block(app, true))
890 return die_ss_("iterator.set_block(app, true)", iterator);
892 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
895 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
896 if(!app->set_data(data, 91, true))
897 return die_("setting APPLICATION data");
898 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
899 return die_("copying object");
900 delete_from_our_metadata_(our_current_position+1);
901 if(!iterator.set_block(app, true))
902 return die_ss_("iterator.set_block(app, true)", iterator);
904 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
907 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
908 if(!app->set_data(data, 100, true))
909 return die_("setting APPLICATION data");
910 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
911 return die_("copying object");
912 delete_from_our_metadata_(our_current_position+1);
913 our_metadata_.blocks[our_current_position]->set_is_last(true);
914 if(!iterator.set_block(app, true))
915 return die_ss_("iterator.set_block(app, true)", iterator);
917 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
920 printf("SV[A]\tset PADDING (equal size)\n");
921 padding->set_length(app->get_length());
922 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
923 return die_("copying object");
924 if(!iterator.set_block(padding, true))
925 return die_ss_("iterator.set_block(padding, true)", iterator);
927 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
930 printf("SV[P]\tinsert PADDING after\n");
931 if(!iterator.insert_block_after(padding, false))
932 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
933 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
936 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
939 printf("SVP[P]\tinsert PADDING after\n");
940 padding->set_length(5);
941 if(!iterator.insert_block_after(padding, false))
942 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
943 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
946 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
949 printf("SVPP[P]\tprev\n");
951 return die_("iterator ended early\n");
952 our_current_position--;
954 printf("SVP[P]P\tprev\n");
956 return die_("iterator ended early\n");
957 our_current_position--;
959 printf("SV[P]PP\tprev\n");
961 return die_("iterator ended early\n");
962 our_current_position--;
964 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
965 if(!app->set_data(data, 101, true))
966 return die_("setting APPLICATION data");
967 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
968 return die_("copying object");
969 if(!iterator.insert_block_after(app, true))
970 return die_ss_("iterator.insert_block_after(app, true)", iterator);
972 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
975 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
976 if(!iterator.delete_block(false))
977 return die_ss_("iterator.delete_block(false)", iterator);
978 delete_from_our_metadata_(our_current_position--);
980 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
983 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
984 if(!app->set_data(data, 97, true))
985 return die_("setting APPLICATION data");
986 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
987 return die_("copying object");
988 if(!iterator.insert_block_after(app, true))
989 return die_ss_("iterator.insert_block_after(app, true)", iterator);
991 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
994 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
995 if(!iterator.delete_block(false))
996 return die_ss_("iterator.delete_block(false)", iterator);
997 delete_from_our_metadata_(our_current_position--);
999 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1002 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1003 if(!app->set_data(data, 100, true))
1004 return die_("setting APPLICATION data");
1005 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1006 return die_("copying object");
1007 delete_from_our_metadata_(our_current_position+1);
1008 if(!iterator.insert_block_after(app, true))
1009 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1011 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1014 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1015 if(!iterator.delete_block(false))
1016 return die_ss_("iterator.delete_block(false)", iterator);
1017 delete_from_our_metadata_(our_current_position--);
1019 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1022 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1023 if(!app->set_data(data, 96, true))
1024 return die_("setting APPLICATION data");
1025 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1026 return die_("copying object");
1027 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1028 if(!iterator.insert_block_after(app, true))
1029 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1031 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1034 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1035 if(!iterator.delete_block(false))
1036 return die_ss_("iterator.delete_block(false)", iterator);
1037 delete_from_our_metadata_(our_current_position--);
1039 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1042 printf("S[V]PP\tnext\n");
1043 if(!iterator.next())
1044 return die_("iterator ended early\n");
1045 our_current_position++;
1047 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1048 if(!iterator.delete_block(false))
1049 return die_ss_("iterator.delete_block(false)", iterator);
1050 delete_from_our_metadata_(our_current_position--);
1052 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1055 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1056 if(!app->set_data(data, 1, true))
1057 return die_("setting APPLICATION data");
1058 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1059 return die_("copying object");
1060 delete_from_our_metadata_(our_current_position+1);
1061 if(!iterator.insert_block_after(app, true))
1062 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1064 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1071 if(!remove_file_(flacfile_))
1077 static bool test_level_2_()
1079 FLAC::Metadata::Prototype *block;
1080 FLAC::Metadata::StreamInfo *streaminfo;
1081 FLAC::Metadata::Application *app;
1082 FLAC::Metadata::Padding *padding;
1083 FLAC__byte data[2000];
1084 unsigned our_current_position;
1086 printf("\n\n++++++ testing level 2 interface\n");
1088 printf("generate read-only file\n");
1090 if(!generate_file_())
1093 if(!change_stats_(flacfile_, /*read_only=*/true))
1096 printf("create chain\n");
1097 FLAC::Metadata::Chain chain;
1098 if(!chain.is_valid())
1099 return die_("allocating memory for chain");
1101 printf("read chain\n");
1103 if(!chain.read(flacfile_))
1104 return die_c_("reading chain", chain.status());
1106 printf("[S]VP\ttest initial metadata\n");
1108 if(!compare_chain_(chain, 0, 0))
1110 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1113 printf("switch file to read-write\n");
1115 if(!change_stats_(flacfile_, /*read-only=*/false))
1118 printf("create iterator\n");
1120 FLAC::Metadata::Iterator iterator;
1121 if(!iterator.is_valid())
1122 return die_("allocating memory for iterator");
1124 our_current_position = 0;
1126 iterator.init(chain);
1128 if(0 == (block = iterator.get_block()))
1129 return die_("getting block from iterator");
1131 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1133 printf("[S]VP\tmodify STREAMINFO, write\n");
1135 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1136 FLAC__ASSERT(0 != streaminfo);
1137 streaminfo->set_sample_rate(32000);
1138 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1139 return die_("copying object");
1141 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/true))
1142 return die_c_("during chain.write(false, true)", chain.status());
1143 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1145 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1148 printf("[S]VP\tnext\n");
1149 if(!iterator.next())
1150 return die_("iterator ended early\n");
1151 our_current_position++;
1153 printf("S[V]P\tnext\n");
1154 if(!iterator.next())
1155 return die_("iterator ended early\n");
1156 our_current_position++;
1158 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1159 if(0 == (block = iterator.get_block()))
1160 return die_("getting block from iterator");
1161 if(0 == (app = new FLAC::Metadata::Application()))
1162 return die_("new FLAC::Metadata::Application()");
1163 app->set_id((const unsigned char *)"duh");
1164 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1165 return die_("setting APPLICATION data");
1166 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1167 return die_("copying object");
1168 if(!iterator.set_block(app))
1169 return die_c_("iterator.set_block(app)", chain.status());
1171 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1172 return die_c_("during chain.write(false, false)", chain.status());
1173 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1175 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1178 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1179 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1180 return die_("copying object");
1181 if(!app->set_data(data, 26, true))
1182 return die_("setting APPLICATION data");
1183 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1184 return die_("copying object");
1185 if(!iterator.set_block(app))
1186 return die_c_("iterator.set_block(app)", chain.status());
1188 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1189 return die_c_("during chain.write(false, false)", chain.status());
1190 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1192 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1195 printf("SV[A]\tgrow 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, 28, 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 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1209 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1212 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1213 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1214 return die_("copying object");
1215 if(!app->set_data(data, 36, true))
1216 return die_("setting APPLICATION data");
1217 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1218 return die_("copying object");
1219 if(!iterator.set_block(app))
1220 return die_c_("iterator.set_block(app)", chain.status());
1222 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1223 return die_c_("during chain.write(false, false)", chain.status());
1224 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1226 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1229 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1230 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1231 return die_("copying object");
1232 if(!app->set_data(data, 33, true))
1233 return die_("setting APPLICATION data");
1234 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1235 return die_("copying object");
1236 if(!iterator.set_block(app))
1237 return die_c_("iterator.set_block(app)", chain.status());
1239 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1240 return die_c_("during chain.write(true, false)", chain.status());
1241 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1243 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1246 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1247 if(0 == (padding = new FLAC::Metadata::Padding()))
1248 return die_("creating PADDING block");
1249 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1250 return die_("copying object");
1251 if(!app->set_data(data, 29, true))
1252 return die_("setting APPLICATION data");
1253 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1254 return die_("copying object");
1255 padding->set_length(0);
1256 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1257 return die_("internal error");
1258 if(!iterator.set_block(app))
1259 return die_c_("iterator.set_block(app)", chain.status());
1261 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1262 return die_c_("during chain.write(true, false)", chain.status());
1263 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1265 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1268 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1269 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1270 return die_("copying object");
1271 if(!app->set_data(data, 16, true))
1272 return die_("setting APPLICATION data");
1273 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1274 return die_("copying object");
1275 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1276 if(!iterator.set_block(app))
1277 return die_c_("iterator.set_block(app)", chain.status());
1279 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1280 return die_c_("during chain.write(true, false)", chain.status());
1281 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1283 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1286 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1287 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1288 return die_("copying object");
1289 if(!app->set_data(data, 50, true))
1290 return die_("setting APPLICATION data");
1291 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1292 return die_("copying object");
1293 if(!iterator.set_block(app))
1294 return die_c_("iterator.set_block(app)", chain.status());
1296 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1297 return die_c_("during chain.write(true, false)", chain.status());
1298 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1300 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1303 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1304 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1305 return die_("copying object");
1306 if(!app->set_data(data, 56, true))
1307 return die_("setting APPLICATION data");
1308 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1309 return die_("copying object");
1310 add_to_padding_length_(our_current_position+1, -(56 - 50));
1311 if(!iterator.set_block(app))
1312 return die_c_("iterator.set_block(app)", chain.status());
1314 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1315 return die_c_("during chain.write(true, false)", chain.status());
1316 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1318 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1321 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1322 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1323 return die_("copying object");
1324 if(!app->set_data(data, 67, true))
1325 return die_("setting APPLICATION data");
1326 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1327 return die_("copying object");
1328 delete_from_our_metadata_(our_current_position+1);
1329 if(!iterator.set_block(app))
1330 return die_c_("iterator.set_block(app)", chain.status());
1332 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1333 return die_c_("during chain.write(true, false)", chain.status());
1334 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1336 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1339 printf("SV[A]\tprev\n");
1340 if(!iterator.prev())
1341 return die_("iterator ended early\n");
1342 our_current_position--;
1344 printf("S[V]A\tprev\n");
1345 if(!iterator.prev())
1346 return die_("iterator ended early\n");
1347 our_current_position--;
1349 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1350 if(0 == (padding = new FLAC::Metadata::Padding()))
1351 return die_("creating PADDING block");
1352 padding->set_length(30);
1353 if(!iterator.insert_block_before(padding))
1354 printf("\titerator.insert_block_before() returned false like it should\n");
1356 return die_("iterator.insert_block_before() should have returned false");
1358 printf("[S]VA\tnext\n");
1359 if(!iterator.next())
1360 return die_("iterator ended early\n");
1361 our_current_position++;
1363 printf("S[V]A\tinsert PADDING after\n");
1364 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1365 return die_("copying metadata");
1366 if(!iterator.insert_block_after(padding))
1367 return die_("iterator.insert_block_after(padding)");
1369 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1372 printf("SV[P]A\tinsert PADDING before\n");
1373 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1374 return die_("creating PADDING block");
1375 padding->set_length(17);
1376 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1377 return die_("copying metadata");
1378 if(!iterator.insert_block_before(padding))
1379 return die_("iterator.insert_block_before(padding)");
1381 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1384 printf("SV[P]PA\tinsert PADDING before\n");
1385 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1386 return die_("creating PADDING block");
1387 padding->set_length(0);
1388 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1389 return die_("copying metadata");
1390 if(!iterator.insert_block_before(padding))
1391 return die_("iterator.insert_block_before(padding)");
1393 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1396 printf("SV[P]PPA\tnext\n");
1397 if(!iterator.next())
1398 return die_("iterator ended early\n");
1399 our_current_position++;
1401 printf("SVP[P]PA\tnext\n");
1402 if(!iterator.next())
1403 return die_("iterator ended early\n");
1404 our_current_position++;
1406 printf("SVPP[P]A\tnext\n");
1407 if(!iterator.next())
1408 return die_("iterator ended early\n");
1409 our_current_position++;
1411 printf("SVPPP[A]\tinsert PADDING after\n");
1412 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1413 return die_("creating PADDING block");
1414 padding->set_length(57);
1415 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1416 return die_("copying metadata");
1417 if(!iterator.insert_block_after(padding))
1418 return die_("iterator.insert_block_after(padding)");
1420 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1423 printf("SVPPPA[P]\tinsert PADDING before\n");
1424 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1425 return die_("creating PADDING block");
1426 padding->set_length(99);
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 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1436 our_current_position = 0;
1438 printf("SVPPPAPP\tmerge padding\n");
1439 chain.merge_padding();
1440 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1441 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1442 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1443 delete_from_our_metadata_(7);
1444 delete_from_our_metadata_(4);
1445 delete_from_our_metadata_(3);
1447 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1448 return die_c_("during chain.write(true, false)", chain.status());
1449 if(!compare_chain_(chain, 0, 0))
1451 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1454 printf("SVPAP\tsort padding\n");
1455 chain.sort_padding();
1456 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1457 delete_from_our_metadata_(2);
1459 if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1460 return die_c_("during chain.write(true, false)", chain.status());
1461 if(!compare_chain_(chain, 0, 0))
1463 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1466 printf("create iterator\n");
1468 FLAC::Metadata::Iterator iterator;
1469 if(!iterator.is_valid())
1470 return die_("allocating memory for iterator");
1472 our_current_position = 0;
1474 iterator.init(chain);
1476 printf("[S]VAP\tnext\n");
1477 if(!iterator.next())
1478 return die_("iterator ended early\n");
1479 our_current_position++;
1481 printf("S[V]AP\tnext\n");
1482 if(!iterator.next())
1483 return die_("iterator ended early\n");
1484 our_current_position++;
1486 printf("SV[A]P\tdelete middle block, replace with padding\n");
1487 if(0 == (padding = new FLAC::Metadata::Padding()))
1488 return die_("creating PADDING block");
1489 padding->set_length(71);
1490 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1491 return die_("copying object");
1492 if(!iterator.delete_block(/*replace_with_padding=*/true))
1493 return die_c_("iterator.delete_block(true)", chain.status());
1495 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1498 printf("S[V]PP\tnext\n");
1499 if(!iterator.next())
1500 return die_("iterator ended early\n");
1501 our_current_position++;
1503 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1504 delete_from_our_metadata_(our_current_position--);
1505 if(!iterator.delete_block(/*replace_with_padding=*/false))
1506 return die_c_("iterator.delete_block(false)", chain.status());
1508 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1511 printf("S[V]P\tnext\n");
1512 if(!iterator.next())
1513 return die_("iterator ended early\n");
1514 our_current_position++;
1516 printf("SV[P]\tdelete last block, replace with padding\n");
1517 if(0 == (padding = new FLAC::Metadata::Padding()))
1518 return die_("creating PADDING block");
1519 padding->set_length(219);
1520 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1521 return die_("copying object");
1522 if(!iterator.delete_block(/*replace_with_padding=*/true))
1523 return die_c_("iterator.delete_block(true)", chain.status());
1525 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1528 printf("S[V]P\tnext\n");
1529 if(!iterator.next())
1530 return die_("iterator ended early\n");
1531 our_current_position++;
1533 printf("SV[P]\tdelete last block, don't replace with padding\n");
1534 delete_from_our_metadata_(our_current_position--);
1535 if(!iterator.delete_block(/*replace_with_padding=*/false))
1536 return die_c_("iterator.delete_block(false)", chain.status());
1538 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1541 printf("S[V]\tprev\n");
1542 if(!iterator.prev())
1543 return die_("iterator ended early\n");
1544 our_current_position--;
1546 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1547 if(iterator.delete_block(/*replace_with_padding=*/false))
1548 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1550 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1554 our_current_position = 0;
1556 printf("SV\tmerge padding\n");
1557 chain.merge_padding();
1559 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1560 return die_c_("during chain.write(false, false)", chain.status());
1561 if(!compare_chain_(chain, 0, 0))
1563 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1566 printf("SV\tsort padding\n");
1567 chain.sort_padding();
1569 if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1570 return die_c_("during chain.write(false, false)", chain.status());
1571 if(!compare_chain_(chain, 0, 0))
1573 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1576 if(!remove_file_(flacfile_))
1582 bool test_metadata_file_manipulation()
1584 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
1586 our_metadata_.num_blocks = 0;
1588 if(!test_level_0_())
1591 if(!test_level_1_())
1594 if(!test_level_2_())