1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "file_utils.h"
22 #include "FLAC/assert.h"
23 #include "FLAC++/decoder.h"
24 #include "FLAC++/metadata.h"
26 #include <stdlib.h> /* for malloc() */
27 #include <string.h> /* for memcpy()/memset() */
29 /******************************************************************************
30 The general strategy of these tests (for interface levels 1 and 2) is
31 to create a dummy FLAC file with a known set of initial metadata
32 blocks, then keep a mirror locally of what we expect the metadata to be
33 after each operation. Then testing becomes a simple matter of running
34 a FLAC__FileDecoder over the dummy file after each operation, comparing
35 the decoded metadata to what's in our local copy. If there are any
36 differences in the metadata, or the actual audio data is corrupted, we
37 will catch it while decoding.
38 ******************************************************************************/
40 class FileDecoder: public FLAC::Decoder::File {
42 inline FileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
44 bool ignore_metadata_;;
47 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
48 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
49 void error_callback(::FLAC__StreamDecoderErrorStatus status);
53 FLAC::Metadata::Prototype *blocks[64];
57 static const char *flacfile_ = "metadata.flac";
59 /* our copy of the metadata in flacfile_ */
60 static OurMetadata our_metadata_;
62 /* the current block number that corresponds to the position of the iterator we are testing */
63 static unsigned mc_our_block_number_ = 0;
65 static bool die_(const char *msg)
67 printf("ERROR: %s\n", msg);
71 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
73 printf("ERROR: %s\n", msg);
74 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
78 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
80 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
81 printf("ERROR: %s\n", msg);
82 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
86 /* functions for working with our metadata copy */
88 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
91 FLAC::Metadata::Prototype *obj = block;
92 FLAC__ASSERT(position < our_metadata_.num_blocks);
94 if(0 == (obj = FLAC::Metadata::clone(block)))
95 return die_("during FLAC::Metadata::clone()");
97 delete our_metadata_.blocks[position];
98 our_metadata_.blocks[position] = obj;
100 /* set the is_last flags */
101 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
102 our_metadata_.blocks[i]->set_is_last(false);
103 our_metadata_.blocks[i]->set_is_last(true);
108 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
111 FLAC::Metadata::Prototype *obj = block;
113 if(0 == (obj = FLAC::Metadata::clone(block)))
114 return die_("during FLAC::Metadata::clone()");
116 if(position > our_metadata_.num_blocks) {
117 position = our_metadata_.num_blocks;
120 for(i = our_metadata_.num_blocks; i > position; i--)
121 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
123 our_metadata_.blocks[position] = obj;
124 our_metadata_.num_blocks++;
126 /* set the is_last flags */
127 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
128 our_metadata_.blocks[i]->set_is_last(false);
129 our_metadata_.blocks[i]->set_is_last(true);
134 static void delete_from_our_metadata_(unsigned position)
137 FLAC__ASSERT(position < our_metadata_.num_blocks);
138 delete our_metadata_.blocks[position];
139 for(i = position; i < our_metadata_.num_blocks - 1; i++)
140 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
141 our_metadata_.num_blocks--;
143 /* set the is_last flags */
144 if(our_metadata_.num_blocks > 0) {
145 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
146 our_metadata_.blocks[i]->set_is_last(false);
147 our_metadata_.blocks[i]->set_is_last(true);
151 /* function for comparing our metadata to a FLAC::Metadata::Chain */
153 static bool compare_chain_(FLAC::Metadata::Chain *chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
156 FLAC::Metadata::Iterator iterator;
157 FLAC::Metadata::Prototype *block;
160 FLAC__ASSERT(0 != chain);
162 printf("\tcomparing chain... ");
165 if(!iterator.is_valid())
166 return die_("allocating memory for iterator");
168 iterator.init(chain);
175 if(0 == (block = iterator.get_block()))
176 return die_("getting block from iterator");
178 if(*block != *our_metadata_.blocks[i])
179 return die_("metadata block mismatch");
182 next_ok = iterator.next();
183 } while(i < our_metadata_.num_blocks && next_ok);
186 return die_("chain has more blocks than expected");
188 if(i < our_metadata_.num_blocks)
189 return die_("short block count in chain");
191 if(0 != current_block) {
192 printf("CURRENT_POSITION... ");
195 if(*current_block != *our_metadata_.blocks[current_position])
196 return die_("metadata block mismatch");
204 ::FLAC__StreamDecoderWriteStatus FileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
209 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
210 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
212 printf("content... ");
216 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
219 void FileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
221 /* don't bother checking if we've already hit an error */
225 printf("%d... ", mc_our_block_number_);
228 if(!ignore_metadata_) {
229 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
230 (void)die_("got more metadata blocks than expected");
231 error_occurred_ = true;
234 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
235 //@@@@if(!::FLAC__metadata_object_is_equal(our_metadata_.blocks[mc_our_block_number_], metadata)) {
236 (void)die_("metadata block mismatch");
237 error_occurred_ = true;
242 mc_our_block_number_++;
245 void FileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
247 error_occurred_ = true;
248 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
251 static bool generate_file_()
253 ::FLAC__StreamMetadata streaminfo, padding;
254 ::FLAC__StreamMetadata *metadata[1];
256 printf("generating FLAC file for test\n");
258 while(our_metadata_.num_blocks > 0)
259 delete_from_our_metadata_(0);
261 streaminfo.is_last = false;
262 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
263 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
264 streaminfo.data.stream_info.min_blocksize = 576;
265 streaminfo.data.stream_info.max_blocksize = 576;
266 streaminfo.data.stream_info.min_framesize = 0;
267 streaminfo.data.stream_info.max_framesize = 0;
268 streaminfo.data.stream_info.sample_rate = 44100;
269 streaminfo.data.stream_info.channels = 1;
270 streaminfo.data.stream_info.bits_per_sample = 8;
271 streaminfo.data.stream_info.total_samples = 0;
272 memset(streaminfo.data.stream_info.md5sum, 0, 16);
274 padding.is_last = true;
275 padding.type = ::FLAC__METADATA_TYPE_PADDING;
276 padding.length = 1234;
278 metadata[0] = &padding;
280 FLAC::Metadata::StreamInfo s(&streaminfo, /*copy=*/false);
281 FLAC::Metadata::Padding p(&padding, /*copy=*/false);
282 if(!insert_to_our_metadata_(&s, 0, /*copy=*/true) || !insert_to_our_metadata_(&p, 1, /*copy=*/true))
283 return die_("priming our metadata");
285 if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
286 return die_("creating the encoded file");
291 static bool test_file_(const char *filename, bool ignore_metadata)
293 FileDecoder decoder(ignore_metadata);
295 FLAC__ASSERT(0 != filename);
297 mc_our_block_number_ = 0;
298 decoder.error_occurred_ = false;
300 printf("\ttesting '%s'... ", filename);
303 if(!decoder.is_valid())
304 return die_("couldn't allocate decoder instance");
306 decoder.set_md5_checking(true);
307 decoder.set_filename(filename);
308 decoder.set_metadata_respond_all();
309 if(decoder.init() != ::FLAC__FILE_DECODER_OK) {
311 return die_("initializing decoder\n");
313 if(!decoder.process_whole_file()) {
315 return die_("decoding file\n");
320 if(decoder.error_occurred_)
323 if(mc_our_block_number_ != our_metadata_.num_blocks)
324 return die_("short metadata block count");
330 static bool change_stats_(const char *filename, bool read_only)
332 if(!file_utils__change_stats(filename, read_only))
333 return die_("during file_utils__change_stats()");
338 static bool remove_file_(const char *filename)
340 while(our_metadata_.num_blocks > 0)
341 delete_from_our_metadata_(0);
343 if(!file_utils__remove_file(filename))
344 return die_("removing file");
349 static bool test_level_0_()
351 FLAC::Metadata::StreamInfo streaminfo;
353 printf("\n\n++++++ testing level 0 interface\n");
355 if(!generate_file_())
358 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
361 if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
362 return die_("during FLAC::Metadata::get_streaminfo()");
364 /* check to see if some basic data matches (c.f. generate_file_()) */
365 if(streaminfo.get_channels() != 1)
366 return die_("mismatch in streaminfo.get_channels()");
367 if(streaminfo.get_bits_per_sample() != 8)
368 return die_("mismatch in streaminfo.get_bits_per_sample()");
369 if(streaminfo.get_sample_rate() != 44100)
370 return die_("mismatch in streaminfo.get_sample_rate()");
371 if(streaminfo.get_min_blocksize() != 576)
372 return die_("mismatch in streaminfo.get_min_blocksize()");
373 if(streaminfo.get_max_blocksize() != 576)
374 return die_("mismatch in streaminfo.get_max_blocksize()");
376 if(!remove_file_(flacfile_))
382 static bool test_level_1_()
384 FLAC::Metadata::Prototype *block;
385 FLAC::Metadata::StreamInfo *streaminfo;
386 FLAC::Metadata::Padding *padding;
387 FLAC::Metadata::Application *app;
388 FLAC__byte data[1000];
389 unsigned our_current_position = 0;
391 printf("\n\n++++++ testing level 1 interface\n");
393 /************************************************************/
395 printf("simple iterator on read-only file\n");
397 if(!generate_file_())
400 if(!change_stats_(flacfile_, /*read_only=*/true))
403 if(!test_file_(flacfile_, /*ignore_metadata=*/true))
406 FLAC::Metadata::SimpleIterator iterator;
408 if(!iterator.is_valid())
409 return die_("iterator.is_valid() returned false");
411 if(!iterator.init(flacfile_, false))
412 return die_("iterator.init() returned false");
414 printf("is writable = %u\n", (unsigned)iterator.is_writable());
415 if(iterator.is_writable())
416 return die_("iterator claims file is writable when it should not be\n");
418 printf("iterate forwards\n");
420 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
421 return die_("expected STREAMINFO type from iterator.get_block_type()");
422 if(0 == (block = iterator.get_block()))
423 return die_("getting block 0");
424 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
425 return die_("expected STREAMINFO type");
426 if(block->get_is_last())
427 return die_("expected is_last to be false");
428 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
429 return die_("bad STREAMINFO length");
430 /* check to see if some basic data matches (c.f. generate_file_()) */
431 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
432 FLAC__ASSERT(0 != streaminfo);
433 if(streaminfo->get_channels() != 1)
434 return die_("mismatch in channels");
435 if(streaminfo->get_bits_per_sample() != 8)
436 return die_("mismatch in bits_per_sample");
437 if(streaminfo->get_sample_rate() != 44100)
438 return die_("mismatch in sample_rate");
439 if(streaminfo->get_min_blocksize() != 576)
440 return die_("mismatch in min_blocksize");
441 if(streaminfo->get_max_blocksize() != 576)
442 return die_("mismatch in max_blocksize");
445 return die_("forward iterator ended early");
446 our_current_position++;
448 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
449 return die_("expected PADDING type from iterator.get_block_type()");
450 if(0 == (block = iterator.get_block()))
451 return die_("getting block 1");
452 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
453 return die_("expected PADDING type");
454 if(!block->get_is_last())
455 return die_("expected is_last to be true");
456 /* check to see if some basic data matches (c.f. generate_file_()) */
457 if(block->get_length() != 1234)
458 return die_("bad PADDING length");
461 return die_("forward iterator returned true but should have returned false");
463 printf("iterate backwards\n");
465 return die_("reverse iterator ended early");
467 return die_("reverse iterator returned true but should have returned false");
469 printf("testing iterator.set_block() on read-only file...\n");
471 if(!iterator.set_block(streaminfo, false))
472 printf("PASSED. iterator.set_block() returned false like it should\n");
474 return die_("iterator.set_block() returned true but shouldn't have");
477 /************************************************************/
479 printf("simple iterator on writable file\n");
481 if(!change_stats_(flacfile_, /*read-only=*/false))
484 printf("creating APPLICATION block\n");
486 if(0 == (app = new FLAC::Metadata::Application()))
487 return die_("new FLAC::Metadata::Application()");
488 app->set_id((const unsigned char *)"duh");
490 printf("creating PADDING block\n");
492 if(0 == (padding = new FLAC::Metadata::Padding()))
493 return die_("new FLAC::Metadata::Padding()");
494 padding->set_length(20);
496 FLAC::Metadata::SimpleIterator iterator;
498 if(!iterator.is_valid())
499 return die_("iterator.is_valid() returned false");
501 if(!iterator.init(flacfile_, /*preserve_file_stats=*/false))
502 return die_("iterator.init() returned false");
503 our_current_position = 0;
505 printf("is writable = %u\n", (unsigned)iterator.is_writable());
507 printf("[S]P\ttry to write over STREAMINFO block...\n");
508 if(!iterator.set_block(app, false))
509 printf("\titerator.set_block() returned false like it should\n");
511 return die_("iterator.set_block() returned true but shouldn't have");
513 printf("[S]P\tnext\n");
515 return die_("iterator ended early\n");
516 our_current_position++;
518 printf("S[P]\tinsert PADDING after, don't expand into padding\n");
519 padding->set_length(25);
520 if(!iterator.insert_block_after(padding, false))
521 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
522 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
525 printf("SP[P]\tprev\n");
527 return die_("iterator ended early\n");
528 our_current_position--;
530 printf("S[P]P\tprev\n");
532 return die_("iterator ended early\n");
533 our_current_position--;
535 printf("[S]PP\tinsert PADDING after, don't expand into padding\n");
536 padding->set_length(30);
537 if(!iterator.insert_block_after(padding, false))
538 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
539 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
542 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
545 printf("S[P]PP\tprev\n");
547 return die_("iterator ended early\n");
548 our_current_position--;
550 printf("[S]PPP\tdelete (STREAMINFO block), must fail\n");
551 if(iterator.delete_block(false))
552 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
554 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
557 printf("[S]PPP\tnext\n");
559 return die_("iterator ended early\n");
560 our_current_position++;
562 printf("S[P]PP\tdelete (middle block), replace with padding\n");
563 if(!iterator.delete_block(true))
564 return die_ss_("iterator.delete_block(true)", iterator);
565 our_current_position--;
567 printf("[S]PPP\tnext\n");
569 return die_("iterator ended early\n");
570 our_current_position++;
572 printf("S[P]PP\tdelete (middle block), don't replace with padding\n");
573 if(!iterator.delete_block(false))
574 return die_ss_("iterator.delete_block(false)", iterator);
575 delete_from_our_metadata_(our_current_position--);
577 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
580 printf("[S]PP\tnext\n");
582 return die_("iterator ended early\n");
583 our_current_position++;
585 printf("S[P]P\tnext\n");
587 return die_("iterator ended early\n");
588 our_current_position++;
590 printf("SP[P]\tdelete (last block), replace with padding\n");
591 if(!iterator.delete_block(true))
592 return die_ss_("iterator.delete_block(false)", iterator);
593 our_current_position--;
595 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
598 printf("S[P]P\tnext\n");
600 return die_("iterator ended early\n");
601 our_current_position++;
603 printf("SP[P]\tdelete (last block), don't replace with padding\n");
604 if(!iterator.delete_block(false))
605 return die_ss_("iterator.delete_block(false)", iterator);
606 delete_from_our_metadata_(our_current_position--);
608 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
611 printf("S[P]\tprev\n");
613 return die_("iterator ended early\n");
614 our_current_position--;
616 printf("[S]P\tset STREAMINFO (change sample rate)\n");
617 FLAC__ASSERT(our_current_position == 0);
618 block = iterator.get_block();
619 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
620 FLAC__ASSERT(0 != streaminfo);
621 streaminfo->set_sample_rate(32000);
622 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
623 return die_("copying object");
624 if(!iterator.set_block(block, false))
625 return die_ss_("iterator.set_block(block, false)", iterator);
628 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
631 printf("[S]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
632 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
633 if(!iterator.insert_block_after(app, true))
634 return die_ss_("iterator.insert_block_after(app, true)", iterator);
635 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
637 our_metadata_.blocks[our_current_position+1]->set_length() = our_metadata_.blocks[our_current_position+1]->get_length() - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
639 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
642 printf("S[A]P\tnext\n");
644 return die_("iterator ended early\n");
645 our_current_position++;
647 printf("SA[P]\tset APPLICATION, expand into padding of exceeding size\n");
648 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
649 if(!iterator.set_block(app, true))
650 return die_ss_("iterator.set_block(app, true)", iterator);
651 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
653 our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
655 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
658 printf("SA[A]P\tset APPLICATION (grow), don't expand into padding\n");
659 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
660 if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
661 return die_("setting APPLICATION data");
662 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
663 return die_("copying object");
664 if(!iterator.set_block(app, false))
665 return die_ss_("iterator.set_block(app, false)", iterator);
667 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
670 printf("SA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
671 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
672 if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
673 return die_("setting APPLICATION data");
674 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
675 return die_("copying object");
676 if(!iterator.set_block(app, false))
677 return die_ss_("iterator.set_block(app, false)", iterator);
679 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
682 printf("SA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
683 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
684 if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
685 return die_("setting APPLICATION data");
686 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
687 return die_("copying object");
688 our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
689 if(!iterator.set_block(app, true))
690 return die_ss_("iterator.set_block(app, true)", iterator);
692 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
695 printf("SA[A]P\tset APPLICATION (shrink), fill in with padding\n");
696 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
697 if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
698 return die_("setting APPLICATION data");
699 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
700 return die_("copying object");
701 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
702 return die_("copying object");
703 our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
704 if(!iterator.set_block(app, true))
705 return die_ss_("iterator.set_block(app, true)", iterator);
707 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
710 printf("SA[A]PP\tnext\n");
712 return die_("iterator ended early\n");
713 our_current_position++;
715 printf("SAA[P]P\tnext\n");
717 return die_("iterator ended early\n");
718 our_current_position++;
720 printf("SAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
722 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
723 return die_("copying object");
724 if(!iterator.set_block(padding, false))
725 return die_ss_("iterator.set_block(padding, false)", iterator);
727 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
730 printf("SAAP[P]\tset APPLICATION (grow)\n");
731 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
732 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
733 return die_("copying object");
734 if(!iterator.set_block(app, false))
735 return die_ss_("iterator.set_block(app, false)", iterator);
737 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
740 printf("SAAP[A]\tset PADDING (equal)\n");
741 padding->length = 27;
742 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
743 return die_("copying object");
744 if(!iterator.set_block(padding, false))
745 return die_ss_("iterator.set_block(padding, false)", iterator);
747 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
750 printf("SAAP[P]\tprev\n");
752 return die_("iterator ended early\n");
753 our_current_position--;
755 printf("SAA[P]P\tdelete (middle block), don't replace with padding\n");
756 if(!iterator.delete_block(false))
757 return die_ss_("iterator.delete_block(false)", iterator);
758 delete_from_our_metadata_(our_current_position--);
760 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
763 printf("SA[A]P\tdelete (middle block), don't replace with padding\n");
764 if(!iterator.delete_block(false))
765 return die_ss_("iterator.delete_block(false)", iterator);
766 delete_from_our_metadata_(our_current_position--);
768 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
771 printf("S[A]P\tnext\n");
773 return die_("iterator ended early\n");
774 our_current_position++;
776 printf("SA[P]\tinsert PADDING after\n");
778 if(!iterator.insert_block_after(padding, false))
779 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
780 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
783 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
786 printf("SAP[P]\tprev\n");
788 return die_("iterator ended early\n");
789 our_current_position--;
791 printf("SA[P]P\tprev\n");
793 return die_("iterator ended early\n");
794 our_current_position--;
796 printf("S[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
797 if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
798 return die_("setting APPLICATION data");
799 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
800 return die_("copying object");
801 if(!iterator.set_block(app, true))
802 return die_ss_("iterator.set_block(app, true)", iterator);
804 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
807 printf("S[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
808 if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
809 return die_("setting APPLICATION data");
810 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
811 return die_("copying object");
812 if(!iterator.set_block(app, true))
813 return die_ss_("iterator.set_block(app, true)", iterator);
815 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
818 printf("S[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
819 if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
820 return die_("setting APPLICATION data");
821 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
822 return die_("copying object");
823 our_metadata_.blocks[our_current_position+1]->length = 0;
824 if(!iterator.set_block(app, true))
825 return die_ss_("iterator.set_block(app, true)", iterator);
827 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
830 printf("S[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
831 if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
832 return die_("setting APPLICATION data");
833 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
834 return die_("copying object");
835 delete_from_our_metadata_(our_current_position+1);
836 if(!iterator.set_block(app, true))
837 return die_ss_("iterator.set_block(app, true)", iterator);
839 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
842 printf("S[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
843 if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
844 return die_("setting APPLICATION data");
845 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
846 return die_("copying object");
847 delete_from_our_metadata_(our_current_position+1);
848 our_metadata_.blocks[our_current_position]->is_last = true;
849 if(!iterator.set_block(app, true))
850 return die_ss_("iterator.set_block(app, true)", iterator);
852 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
855 printf("S[A]\tset PADDING (equal size)\n");
856 padding->length = app->length;
857 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
858 return die_("copying object");
859 if(!iterator.set_block(padding, true))
860 return die_ss_("iterator.set_block(padding, true)", iterator);
862 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
865 printf("S[P]\tinsert PADDING after\n");
866 if(!iterator.insert_block_after(padding, false))
867 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
868 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
871 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
874 printf("SP[P]\tinsert PADDING after\n");
876 if(!iterator.insert_block_after(padding, false))
877 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
878 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
881 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
884 printf("SPP[P]\tprev\n");
886 return die_("iterator ended early\n");
887 our_current_position--;
889 printf("SP[P]P\tprev\n");
891 return die_("iterator ended early\n");
892 our_current_position--;
894 printf("S[P]PP\tprev\n");
896 return die_("iterator ended early\n");
897 our_current_position--;
899 printf("[S]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
900 if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
901 return die_("setting APPLICATION data");
902 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
903 return die_("copying object");
904 if(!iterator.insert_block_after(app, true))
905 return die_ss_("iterator.insert_block_after(app, true)", iterator);
907 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
910 printf("S[A]PPP\tdelete (middle block), don't replace with padding\n");
911 if(!iterator.delete_block(false))
912 return die_ss_("iterator.delete_block(false)", iterator);
913 delete_from_our_metadata_(our_current_position--);
915 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
918 printf("[S]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
919 if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
920 return die_("setting APPLICATION data");
921 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
922 return die_("copying object");
923 if(!iterator.insert_block_after(app, true))
924 return die_ss_("iterator.insert_block_after(app, true)", iterator);
926 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
929 printf("S[A]PPP\tdelete (middle block), don't replace with padding\n");
930 if(!iterator.delete_block(false))
931 return die_ss_("iterator.delete_block(false)", iterator);
932 delete_from_our_metadata_(our_current_position--);
934 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
937 printf("[S]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
938 if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
939 return die_("setting APPLICATION data");
940 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
941 return die_("copying object");
942 delete_from_our_metadata_(our_current_position+1);
943 if(!iterator.insert_block_after(app, true))
944 return die_ss_("iterator.insert_block_after(app, true)", iterator);
946 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
949 printf("S[A]PP\tdelete (middle block), don't replace with padding\n");
950 if(!iterator.delete_block(false))
951 return die_ss_("iterator.delete_block(false)", iterator);
952 delete_from_our_metadata_(our_current_position--);
954 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
957 printf("[S]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
958 if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
959 return die_("setting APPLICATION data");
960 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
961 return die_("copying object");
962 our_metadata_.blocks[our_current_position+1]->length = 0;
963 if(!iterator.insert_block_after(app, true))
964 return die_ss_("iterator.insert_block_after(app, true)", iterator);
966 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
969 printf("S[A]PP\tdelete (middle block), don't replace with padding\n");
970 if(!iterator.delete_block(false))
971 return die_ss_("iterator.delete_block(false)", iterator);
972 delete_from_our_metadata_(our_current_position--);
974 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
977 printf("[S]PP\tnext\n");
979 return die_("iterator ended early\n");
980 our_current_position++;
982 printf("S[P]P\tdelete (middle block), don't replace with padding\n");
983 if(!iterator.delete_block(false))
984 return die_ss_("iterator.delete_block(false)", iterator);
985 delete_from_our_metadata_(our_current_position--);
987 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
990 printf("[S]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
991 if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
992 return die_("setting APPLICATION data");
993 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
994 return die_("copying object");
995 delete_from_our_metadata_(our_current_position+1);
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("delete simple iterator\n");
1007 FLAC__metadata_object_delete(app);
1008 FLAC__metadata_object_delete(padding);
1010 if(!remove_file_(flacfile_))
1016 static bool test_level_2_()
1018 FLAC__Metadata_Iterator *iterator;
1019 FLAC__Metadata_Chain *chain;
1020 FLAC__StreamMetadata *block, *app, *padding;
1021 FLAC__byte data[2000];
1022 unsigned our_current_position;
1024 printf("\n\n++++++ testing level 2 interface\n");
1026 printf("generate read-only file\n");
1028 if(!generate_file_())
1031 if(!change_stats_(flacfile_, /*read_only=*/true))
1034 printf("create chain\n");
1036 if(0 == (chain = chain.new()))
1037 return die_("allocating chain");
1039 printf("read chain\n");
1041 if(!chain.read(chain, flacfile_))
1042 return die_c_("reading chain", chain.status(chain));
1044 printf("[S]P\ttest initial metadata\n");
1046 if(!compare_chain_(chain, 0, 0))
1048 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1051 printf("switch file to read-write\n");
1053 if(!change_stats_(flacfile_, /*read-only=*/false))
1056 printf("create iterator\n");
1057 if(0 == (iterator = iterator.new()))
1058 return die_("allocating memory for iterator");
1060 our_current_position = 0;
1062 iterator.init(chain);
1064 if(0 == (block = iterator.get_block()))
1065 return die_("getting block from iterator");
1067 FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1069 printf("[S]P\tmodify STREAMINFO, write\n");
1071 block->data.stream_info.sample_rate = 32000;
1072 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1073 return die_("copying object");
1075 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/true))
1076 return die_c_("during chain.write(chain, false, true)", chain.status(chain));
1077 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1079 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1082 printf("[S]P\tnext\n");
1083 if(!iterator.next())
1084 return die_("iterator ended early\n");
1085 our_current_position++;
1087 printf("S[P]\treplace PADDING with identical-size APPLICATION\n");
1088 if(0 == (block = iterator.get_block()))
1089 return die_("getting block from iterator");
1090 if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1091 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1092 memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1093 if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1094 return die_("setting APPLICATION data");
1095 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1096 return die_("copying object");
1097 if(!iterator.set_block(app))
1098 return die_c_("iterator.set_block(app)", chain.status(chain));
1100 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1101 return die_c_("during chain.write(chain, false, false)", chain.status(chain));
1102 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1104 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1107 printf("S[A]\tshrink APPLICATION, don't use padding\n");
1108 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1109 return die_("copying object");
1110 if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1111 return die_("setting APPLICATION data");
1112 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1113 return die_("copying object");
1114 if(!iterator.set_block(app))
1115 return die_c_("iterator.set_block(app)", chain.status(chain));
1117 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1118 return die_c_("during chain.write(chain, false, false)", chain.status(chain));
1119 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1121 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1124 printf("S[A]\tgrow APPLICATION, don't use padding\n");
1125 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1126 return die_("copying object");
1127 if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1128 return die_("setting APPLICATION data");
1129 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1130 return die_("copying object");
1131 if(!iterator.set_block(app))
1132 return die_c_("iterator.set_block(app)", chain.status(chain));
1134 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1135 return die_c_("during chain.write(chain, false, false)", chain.status(chain));
1136 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1138 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1141 printf("S[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1142 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1143 return die_("copying object");
1144 if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1145 return die_("setting APPLICATION data");
1146 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1147 return die_("copying object");
1148 if(!iterator.set_block(app))
1149 return die_c_("iterator.set_block(app)", chain.status(chain));
1151 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1152 return die_c_("during chain.write(chain, false, false)", chain.status(chain));
1153 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1155 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1158 printf("S[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1159 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1160 return die_("copying object");
1161 if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1162 return die_("setting APPLICATION data");
1163 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1164 return die_("copying object");
1165 if(!iterator.set_block(app))
1166 return die_c_("iterator.set_block(app)", chain.status(chain));
1168 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1169 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1170 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1172 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1175 printf("S[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1176 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1177 return die_("creating PADDING block");
1178 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1179 return die_("copying object");
1180 if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1181 return die_("setting APPLICATION data");
1182 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1183 return die_("copying object");
1184 padding->length = 0;
1185 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1186 return die_("internal error");
1187 if(!iterator.set_block(app))
1188 return die_c_("iterator.set_block(app)", chain.status(chain));
1190 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1191 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1192 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1194 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1197 printf("S[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1198 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1199 return die_("copying object");
1200 if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1201 return die_("setting APPLICATION data");
1202 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1203 return die_("copying object");
1204 our_metadata_.blocks[our_current_position+1]->length = 13;
1205 if(!iterator.set_block(app))
1206 return die_c_("iterator.set_block(app)", chain.status(chain));
1208 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1209 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1210 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1212 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1215 printf("S[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1216 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1217 return die_("copying object");
1218 if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1219 return die_("setting APPLICATION data");
1220 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1221 return die_("copying object");
1222 if(!iterator.set_block(app))
1223 return die_c_("iterator.set_block(app)", chain.status(chain));
1225 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1226 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1227 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1229 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1232 printf("S[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1233 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1234 return die_("copying object");
1235 if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1236 return die_("setting APPLICATION data");
1237 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1238 return die_("copying object");
1239 our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1240 if(!iterator.set_block(app))
1241 return die_c_("iterator.set_block(app)", chain.status(chain));
1243 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1244 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1245 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1247 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1250 printf("S[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1251 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1252 return die_("copying object");
1253 if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1254 return die_("setting APPLICATION data");
1255 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1256 return die_("copying object");
1257 delete_from_our_metadata_(our_current_position+1);
1258 if(!iterator.set_block(app))
1259 return die_c_("iterator.set_block(app)", chain.status(chain));
1261 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1262 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1263 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1265 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1268 printf("S[A]\tprev\n");
1269 if(!iterator.prev())
1270 return die_("iterator ended early\n");
1271 our_current_position--;
1273 printf("[S]A\tinsert PADDING before STREAMINFO (should fail)\n");
1274 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1275 return die_("creating PADDING block");
1276 padding->length = 30;
1277 if(!iterator.insert_block_before(padding))
1278 printf("\titerator.insert_block_before() returned false like it should\n");
1280 return die_("iterator.insert_block_before() should have returned false");
1282 printf("[S]A\tinsert PADDING after\n");
1283 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1284 return die_("copying metadata");
1285 if(!iterator.insert_block_after(padding))
1286 return die_("iterator.insert_block_after(padding)");
1288 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1291 printf("S[P]A\tinsert PADDING before\n");
1292 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1293 return die_("creating PADDING block");
1294 padding->length = 17;
1295 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1296 return die_("copying metadata");
1297 if(!iterator.insert_block_before(padding))
1298 return die_("iterator.insert_block_before(padding)");
1300 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1303 printf("S[P]PA\tinsert PADDING before\n");
1304 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1305 return die_("creating PADDING block");
1306 padding->length = 0;
1307 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1308 return die_("copying metadata");
1309 if(!iterator.insert_block_before(padding))
1310 return die_("iterator.insert_block_before(padding)");
1312 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1315 printf("S[P]PPA\tnext\n");
1316 if(!iterator.next())
1317 return die_("iterator ended early\n");
1318 our_current_position++;
1320 printf("SP[P]PA\tnext\n");
1321 if(!iterator.next())
1322 return die_("iterator ended early\n");
1323 our_current_position++;
1325 printf("SPP[P]A\tnext\n");
1326 if(!iterator.next())
1327 return die_("iterator ended early\n");
1328 our_current_position++;
1330 printf("SPPP[A]\tinsert PADDING after\n");
1331 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[1])))
1332 return die_("creating PADDING block");
1333 padding->length = 57;
1334 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1335 return die_("copying metadata");
1336 if(!iterator.insert_block_after(padding))
1337 return die_("iterator.insert_block_after(padding)");
1339 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1342 printf("SPPPA[P]\tinsert PADDING before\n");
1343 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[1])))
1344 return die_("creating PADDING block");
1345 padding->length = 99;
1346 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1347 return die_("copying metadata");
1348 if(!iterator.insert_block_before(padding))
1349 return die_("iterator.insert_block_before(padding)");
1351 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1354 printf("delete iterator\n");
1356 our_current_position = 0;
1358 printf("SPPPAPP\tmerge padding\n");
1359 chain.merge_padding(chain);
1360 our_metadata_.blocks[1]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1361 our_metadata_.blocks[1]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1362 our_metadata_.blocks[5]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[6]->length);
1363 delete_from_our_metadata_(6);
1364 delete_from_our_metadata_(3);
1365 delete_from_our_metadata_(2);
1367 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1368 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1369 if(!compare_chain_(chain, 0, 0))
1371 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1374 printf("SPAP\tsort padding\n");
1375 chain.sort_padding(chain);
1376 our_metadata_.blocks[3]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[1]->length);
1377 delete_from_our_metadata_(1);
1379 if(!chain.write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1380 return die_c_("during chain.write(chain, true, false)", chain.status(chain));
1381 if(!compare_chain_(chain, 0, 0))
1383 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1386 printf("create iterator\n");
1387 if(0 == (iterator = iterator.new()))
1388 return die_("allocating memory for iterator");
1390 our_current_position = 0;
1392 iterator.init(chain);
1394 printf("[S]AP\tnext\n");
1395 if(!iterator.next())
1396 return die_("iterator ended early\n");
1397 our_current_position++;
1399 printf("S[A]P\tdelete middle block, replace with padding\n");
1400 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1401 return die_("creating PADDING block");
1402 padding->length = 71;
1403 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1404 return die_("copying object");
1405 if(!iterator.delete_block(/*replace_with_padding=*/true))
1406 return die_c_("iterator.delete_block(true)", chain.status(chain));
1408 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1411 printf("[S]PP\tnext\n");
1412 if(!iterator.next())
1413 return die_("iterator ended early\n");
1414 our_current_position++;
1416 printf("S[P]P\tdelete middle block, don't replace with padding\n");
1417 delete_from_our_metadata_(our_current_position--);
1418 if(!iterator.delete_block(/*replace_with_padding=*/false))
1419 return die_c_("iterator.delete_block(false)", chain.status(chain));
1421 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1424 printf("[S]P\tnext\n");
1425 if(!iterator.next())
1426 return die_("iterator ended early\n");
1427 our_current_position++;
1429 printf("S[P]\tdelete last block, replace with padding\n");
1430 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1431 return die_("creating PADDING block");
1432 padding->length = 219;
1433 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1434 return die_("copying object");
1435 if(!iterator.delete_block(/*replace_with_padding=*/true))
1436 return die_c_("iterator.delete_block(true)", chain.status(chain));
1438 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1441 printf("[S]P\tnext\n");
1442 if(!iterator.next())
1443 return die_("iterator ended early\n");
1444 our_current_position++;
1446 printf("S[P]\tdelete last block, don't replace with padding\n");
1447 delete_from_our_metadata_(our_current_position--);
1448 if(!iterator.delete_block(/*replace_with_padding=*/false))
1449 return die_c_("iterator.delete_block(false)", chain.status(chain));
1451 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1454 printf("[S]\tdelete STREAMINFO block, should fail\n");
1455 if(iterator.delete_block(/*replace_with_padding=*/false))
1456 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1458 if(!compare_chain_(chain, our_current_position, iterator.get_block()))
1461 printf("delete iterator\n");
1463 our_current_position = 0;
1465 printf("S\tmerge padding\n");
1466 chain.merge_padding(chain);
1468 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1469 return die_c_("during chain.write(chain, false, false)", chain.status(chain));
1470 if(!compare_chain_(chain, 0, 0))
1472 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1475 printf("S\tsort padding\n");
1476 chain.sort_padding(chain);
1478 if(!chain.write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1479 return die_c_("during chain.write(chain, false, false)", chain.status(chain));
1480 if(!compare_chain_(chain, 0, 0))
1482 if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1485 printf("delete chain\n");
1487 chain.delete(chain);
1489 if(!remove_file_(flacfile_))
1495 bool test_metadata_file_manipulation()
1497 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
1499 our_metadata_.num_blocks = 0;
1501 if(!test_level_0_())
1504 if(!test_level_1_())
1507 if(!test_level_2_())