add new/missing files
[flac.git] / src / test_libFLAC++ / metadata_manip.cpp
1 /* test_libFLAC++ - Unit tester for libFLAC++
2  * Copyright (C) 2002,2003  Josh Coalson
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 extern "C" {
20 #include "file_utils.h"
21 }
22 #include "FLAC/assert.h"
23 #include "FLAC++/decoder.h"
24 #include "FLAC++/metadata.h"
25 #include "share/grabbag.h"
26 #include <stdio.h>
27 #include <stdlib.h> /* for malloc() */
28 #include <string.h> /* for memcpy()/memset() */
29
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 ******************************************************************************/
40
41 class OurFileDecoder: public FLAC::Decoder::File {
42 public:
43         inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
44
45         bool ignore_metadata_;;
46         bool error_occurred_;
47 protected:
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);
51 };
52
53 struct OurMetadata {
54         FLAC::Metadata::Prototype *blocks[64];
55         unsigned num_blocks;
56 };
57
58 static const char *flacfile_ = "metadata.flac";
59
60 /* our copy of the metadata in flacfile_ */
61 static OurMetadata our_metadata_;
62
63 /* the current block number that corresponds to the position of the iterator we are testing */
64 static unsigned mc_our_block_number_ = 0;
65
66 static bool die_(const char *msg)
67 {
68         printf("ERROR: %s\n", msg);
69         return false;
70 }
71
72 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
73 {
74         printf("ERROR: %s\n", msg);
75         printf("       status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
76         return false;
77 }
78
79 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
80 {
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());
84         return false;
85 }
86
87 static void *malloc_or_die_(size_t size)
88 {
89         void *x = malloc(size);
90         if(0 == x) {
91                 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
92                 exit(1);
93         }
94         return x;
95 }
96
97 /* functions for working with our metadata copy */
98
99 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
100 {
101         unsigned i;
102         FLAC::Metadata::Prototype *obj = block;
103         FLAC__ASSERT(position < our_metadata_.num_blocks);
104         if(copy) {
105                 if(0 == (obj = FLAC::Metadata::clone(block)))
106                         return die_("during FLAC::Metadata::clone()");
107         }
108         delete our_metadata_.blocks[position];
109         our_metadata_.blocks[position] = obj;
110
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);
115
116         return true;
117 }
118
119 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
120 {
121         unsigned i;
122         FLAC::Metadata::Prototype *obj = block;
123         if(copy) {
124                 if(0 == (obj = FLAC::Metadata::clone(block)))
125                         return die_("during FLAC::Metadata::clone()");
126         }
127         if(position > our_metadata_.num_blocks) {
128                 position = our_metadata_.num_blocks;
129         }
130         else {
131                 for(i = our_metadata_.num_blocks; i > position; i--)
132                         our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
133         }
134         our_metadata_.blocks[position] = obj;
135         our_metadata_.num_blocks++;
136
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);
141
142         return true;
143 }
144
145 static void delete_from_our_metadata_(unsigned position)
146 {
147         unsigned i;
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--;
153
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);
159         }
160 }
161
162 void add_to_padding_length_(unsigned index, int delta)
163 {
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));
167 }
168
169 /* function for comparing our metadata to a FLAC::Metadata::Chain */
170
171 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
172 {
173         unsigned i;
174         FLAC::Metadata::Iterator iterator;
175         bool next_ok = true;
176
177         printf("\tcomparing chain... ");
178         fflush(stdout);
179
180         if(!iterator.is_valid())
181                 return die_("allocating memory for iterator");
182
183         iterator.init(chain);
184
185         i = 0;
186         do {
187                 FLAC::Metadata::Prototype *block;
188
189                 printf("%u... ", i);
190                 fflush(stdout);
191
192                 if(0 == (block = iterator.get_block()))
193                         return die_("getting block from iterator");
194
195                 if(*block != *our_metadata_.blocks[i])
196                         return die_("metadata block mismatch");
197
198                 delete block;
199                 i++;
200                 next_ok = iterator.next();
201         } while(i < our_metadata_.num_blocks && next_ok);
202
203         if(next_ok)
204                 return die_("chain has more blocks than expected");
205
206         if(i < our_metadata_.num_blocks)
207                 return die_("short block count in chain");
208
209         if(0 != current_block) {
210                 printf("CURRENT_POSITION... ");
211                 fflush(stdout);
212
213                 if(*current_block != *our_metadata_.blocks[current_position])
214                         return die_("metadata block mismatch");
215         }
216
217         printf("PASSED\n");
218
219         return true;
220 }
221
222 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
223 {
224         (void)buffer;
225
226         if(
227                 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
228                 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
229         ) {
230                 printf("content... ");
231                 fflush(stdout);
232         }
233
234         return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
235 }
236
237 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
238 {
239         /* don't bother checking if we've already hit an error */
240         if(error_occurred_)
241                 return;
242
243         printf("%d... ", mc_our_block_number_);
244         fflush(stdout);
245
246         if(!ignore_metadata_) {
247                 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
248                         (void)die_("got more metadata blocks than expected");
249                         error_occurred_ = true;
250                 }
251                 else {
252                         if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
253                                 (void)die_("metadata block mismatch");
254                                 error_occurred_ = true;
255                         }
256                 }
257         }
258
259         mc_our_block_number_++;
260 }
261
262 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
263 {
264         error_occurred_ = true;
265         printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
266 }
267
268 static bool generate_file_()
269 {
270         ::FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
271         ::FLAC__StreamMetadata *metadata[1];
272
273         printf("generating FLAC file for test\n");
274
275         while(our_metadata_.num_blocks > 0)
276                 delete_from_our_metadata_(0);
277
278         streaminfo.is_last = false;
279         streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
280         streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
281         streaminfo.data.stream_info.min_blocksize = 576;
282         streaminfo.data.stream_info.max_blocksize = 576;
283         streaminfo.data.stream_info.min_framesize = 0;
284         streaminfo.data.stream_info.max_framesize = 0;
285         streaminfo.data.stream_info.sample_rate = 44100;
286         streaminfo.data.stream_info.channels = 1;
287         streaminfo.data.stream_info.bits_per_sample = 8;
288         streaminfo.data.stream_info.total_samples = 0;
289         memset(streaminfo.data.stream_info.md5sum, 0, 16);
290
291         {
292                 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
293                 vorbiscomment.is_last = false;
294                 vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
295                 vorbiscomment.length = (4 + vendor_string_length) + 4;
296                 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
297                 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length);
298                 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
299                 vorbiscomment.data.vorbis_comment.num_comments = 0;
300                 vorbiscomment.data.vorbis_comment.comments = 0;
301         }
302
303         padding.is_last = true;
304         padding.type = ::FLAC__METADATA_TYPE_PADDING;
305         padding.length = 1234;
306
307         metadata[0] = &padding;
308
309         FLAC::Metadata::StreamInfo s(&streaminfo);
310         FLAC::Metadata::VorbisComment v(&vorbiscomment);
311         FLAC::Metadata::Padding p(&padding);
312         if(
313                 !insert_to_our_metadata_(&s, 0, /*copy=*/true) ||
314                 !insert_to_our_metadata_(&v, 1, /*copy=*/true) ||
315                 !insert_to_our_metadata_(&p, 2, /*copy=*/true)
316         )
317                 return die_("priming our metadata");
318
319         if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
320                 return die_("creating the encoded file");
321
322         free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
323
324         return true;
325 }
326
327 static bool test_file_(const char *filename, bool ignore_metadata)
328 {
329         OurFileDecoder decoder(ignore_metadata);
330
331         FLAC__ASSERT(0 != filename);
332
333         mc_our_block_number_ = 0;
334         decoder.error_occurred_ = false;
335
336         printf("\ttesting '%s'... ", filename);
337         fflush(stdout);
338
339         if(!decoder.is_valid())
340                 return die_("couldn't allocate decoder instance");
341
342         decoder.set_md5_checking(true);
343         decoder.set_filename(filename);
344         decoder.set_metadata_respond_all();
345         if(decoder.init() != ::FLAC__FILE_DECODER_OK) {
346                 decoder.finish();
347                 return die_("initializing decoder\n");
348         }
349         if(!decoder.process_until_end_of_file()) {
350                 decoder.finish();
351                 return die_("decoding file\n");
352         }
353
354         decoder.finish();
355
356         if(decoder.error_occurred_)
357                 return false;
358
359         if(mc_our_block_number_ != our_metadata_.num_blocks)
360                 return die_("short metadata block count");
361
362         printf("PASSED\n");
363         return true;
364 }
365
366 static bool change_stats_(const char *filename, bool read_only)
367 {
368         if(!grabbag__file_change_stats(filename, read_only))
369                 return die_("during grabbag__file_change_stats()");
370
371         return true;
372 }
373
374 static bool remove_file_(const char *filename)
375 {
376         while(our_metadata_.num_blocks > 0)
377                 delete_from_our_metadata_(0);
378
379         if(!grabbag__file_remove_file(filename))
380                 return die_("removing file");
381
382         return true;
383 }
384
385 static bool test_level_0_()
386 {
387         FLAC::Metadata::StreamInfo streaminfo;
388
389         printf("\n\n++++++ testing level 0 interface\n");
390
391         if(!generate_file_())
392                 return false;
393
394         if(!test_file_(flacfile_, /*ignore_metadata=*/true))
395                 return false;
396
397         if(!FLAC::Metadata::get_streaminfo(flacfile_, streaminfo))
398                 return die_("during FLAC::Metadata::get_streaminfo()");
399
400         /* check to see if some basic data matches (c.f. generate_file_()) */
401         if(streaminfo.get_channels() != 1)
402                 return die_("mismatch in streaminfo.get_channels()");
403         if(streaminfo.get_bits_per_sample() != 8)
404                 return die_("mismatch in streaminfo.get_bits_per_sample()");
405         if(streaminfo.get_sample_rate() != 44100)
406                 return die_("mismatch in streaminfo.get_sample_rate()");
407         if(streaminfo.get_min_blocksize() != 576)
408                 return die_("mismatch in streaminfo.get_min_blocksize()");
409         if(streaminfo.get_max_blocksize() != 576)
410                 return die_("mismatch in streaminfo.get_max_blocksize()");
411
412         if(!remove_file_(flacfile_))
413                 return false;
414
415         return true;
416 }
417
418 static bool test_level_1_()
419 {
420         FLAC::Metadata::Prototype *block;
421         FLAC::Metadata::StreamInfo *streaminfo;
422         FLAC::Metadata::Padding *padding;
423         FLAC::Metadata::Application *app;
424         FLAC__byte data[1000];
425         unsigned our_current_position = 0;
426
427         // initialize 'data' to avoid Valgrind errors
428         memset(data, 0, sizeof(data));
429
430         printf("\n\n++++++ testing level 1 interface\n");
431
432         /************************************************************/
433         {
434         printf("simple iterator on read-only file\n");
435
436         if(!generate_file_())
437                 return false;
438
439         if(!change_stats_(flacfile_, /*read_only=*/true))
440                 return false;
441
442         if(!test_file_(flacfile_, /*ignore_metadata=*/true))
443                 return false;
444
445         FLAC::Metadata::SimpleIterator iterator;
446
447         if(!iterator.is_valid())
448                 return die_("iterator.is_valid() returned false");
449
450         if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
451                 return die_("iterator.init() returned false");
452
453         printf("is writable = %u\n", (unsigned)iterator.is_writable());
454         if(iterator.is_writable())
455                 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
456
457         printf("iterate forwards\n");
458
459         if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
460                 return die_("expected STREAMINFO type from iterator.get_block_type()");
461         if(0 == (block = iterator.get_block()))
462                 return die_("getting block 0");
463         if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
464                 return die_("expected STREAMINFO type");
465         if(block->get_is_last())
466                 return die_("expected is_last to be false");
467         if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
468                 return die_("bad STREAMINFO length");
469         /* check to see if some basic data matches (c.f. generate_file_()) */
470         streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
471         FLAC__ASSERT(0 != streaminfo);
472         if(streaminfo->get_channels() != 1)
473                 return die_("mismatch in channels");
474         if(streaminfo->get_bits_per_sample() != 8)
475                 return die_("mismatch in bits_per_sample");
476         if(streaminfo->get_sample_rate() != 44100)
477                 return die_("mismatch in sample_rate");
478         if(streaminfo->get_min_blocksize() != 576)
479                 return die_("mismatch in min_blocksize");
480         if(streaminfo->get_max_blocksize() != 576)
481                 return die_("mismatch in max_blocksize");
482         // we will delete streaminfo a little later when we're really done with it...
483
484         if(!iterator.next())
485                 return die_("forward iterator ended early");
486         our_current_position++;
487
488         if(!iterator.next())
489                 return die_("forward iterator ended early");
490         our_current_position++;
491
492         if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
493                 return die_("expected PADDING type from iterator.get_block_type()");
494         if(0 == (block = iterator.get_block()))
495                 return die_("getting block 1");
496         if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
497                 return die_("expected PADDING type");
498         if(!block->get_is_last())
499                 return die_("expected is_last to be true");
500         /* check to see if some basic data matches (c.f. generate_file_()) */
501         if(block->get_length() != 1234)
502                 return die_("bad PADDING length");
503         delete block;
504
505         if(iterator.next())
506                 return die_("forward iterator returned true but should have returned false");
507
508         printf("iterate backwards\n");
509         if(!iterator.prev())
510                 return die_("reverse iterator ended early");
511         if(!iterator.prev())
512                 return die_("reverse iterator ended early");
513         if(iterator.prev())
514                 return die_("reverse iterator returned true but should have returned false");
515
516         printf("testing iterator.set_block() on read-only file...\n");
517
518         if(!iterator.set_block(streaminfo, false))
519                 printf("PASSED.  iterator.set_block() returned false like it should\n");
520         else
521                 return die_("iterator.set_block() returned true but shouldn't have");
522         delete streaminfo;
523         }
524
525         /************************************************************/
526         {
527         printf("simple iterator on writable file\n");
528
529         if(!change_stats_(flacfile_, /*read-only=*/false))
530                 return false;
531
532         printf("creating APPLICATION block\n");
533
534         if(0 == (app = new FLAC::Metadata::Application()))
535                 return die_("new FLAC::Metadata::Application()");
536         app->set_id((const unsigned char *)"duh");
537
538         printf("creating PADDING block\n");
539
540         if(0 == (padding = new FLAC::Metadata::Padding()))
541                 return die_("new FLAC::Metadata::Padding()");
542         padding->set_length(20);
543
544         FLAC::Metadata::SimpleIterator iterator;
545
546         if(!iterator.is_valid())
547                 return die_("iterator.is_valid() returned false");
548
549         if(!iterator.init(flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
550                 return die_("iterator.init() returned false");
551         our_current_position = 0;
552
553         printf("is writable = %u\n", (unsigned)iterator.is_writable());
554
555         printf("[S]VP\ttry to write over STREAMINFO block...\n");
556         if(!iterator.set_block(app, false))
557                 printf("\titerator.set_block() returned false like it should\n");
558         else
559                 return die_("iterator.set_block() returned true but shouldn't have");
560
561         printf("[S]VP\tnext\n");
562         if(!iterator.next())
563                 return die_("iterator ended early\n");
564         our_current_position++;
565
566         printf("S[V]P\tnext\n");
567         if(!iterator.next())
568                 return die_("iterator ended early\n");
569         our_current_position++;
570
571         printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
572         padding->set_length(25);
573         if(!iterator.insert_block_after(padding, false))
574                 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
575         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
576                 return false;
577
578         printf("SVP[P]\tprev\n");
579         if(!iterator.prev())
580                 return die_("iterator ended early\n");
581         our_current_position--;
582
583         printf("SV[P]P\tprev\n");
584         if(!iterator.prev())
585                 return die_("iterator ended early\n");
586         our_current_position--;
587
588         printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
589         padding->set_length(30);
590         if(!iterator.insert_block_after(padding, false))
591                 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
592         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
593                 return false;
594
595         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
596                 return false;
597
598         printf("SV[P]PP\tprev\n");
599         if(!iterator.prev())
600                 return die_("iterator ended early\n");
601         our_current_position--;
602
603         printf("S[V]PPP\tprev\n");
604         if(!iterator.prev())
605                 return die_("iterator ended early\n");
606         our_current_position--;
607
608         printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
609         if(iterator.delete_block(false))
610                 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
611
612         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
613                 return false;
614
615         printf("[S]VPPP\tnext\n");
616         if(!iterator.next())
617                 return die_("iterator ended early\n");
618         our_current_position++;
619
620         printf("S[V]PPP\tnext\n");
621         if(!iterator.next())
622                 return die_("iterator ended early\n");
623         our_current_position++;
624
625         printf("SV[P]PP\tdelete (middle block), replace with padding\n");
626         if(!iterator.delete_block(true))
627                 return die_ss_("iterator.delete_block(true)", iterator);
628         our_current_position--;
629
630         printf("S[V]PPP\tnext\n");
631         if(!iterator.next())
632                 return die_("iterator ended early\n");
633         our_current_position++;
634
635         printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
636         if(!iterator.delete_block(false))
637                 return die_ss_("iterator.delete_block(false)", iterator);
638         delete_from_our_metadata_(our_current_position--);
639
640         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
641                 return false;
642
643         printf("S[V]PP\tnext\n");
644         if(!iterator.next())
645                 return die_("iterator ended early\n");
646         our_current_position++;
647
648         printf("SV[P]P\tnext\n");
649         if(!iterator.next())
650                 return die_("iterator ended early\n");
651         our_current_position++;
652
653         printf("SVP[P]\tdelete (last block), replace with padding\n");
654         if(!iterator.delete_block(true))
655                 return die_ss_("iterator.delete_block(false)", iterator);
656         our_current_position--;
657
658         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
659                 return false;
660
661         printf("SV[P]P\tnext\n");
662         if(!iterator.next())
663                 return die_("iterator ended early\n");
664         our_current_position++;
665
666         printf("SVP[P]\tdelete (last block), don't replace with padding\n");
667         if(!iterator.delete_block(false))
668                 return die_ss_("iterator.delete_block(false)", iterator);
669         delete_from_our_metadata_(our_current_position--);
670
671         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
672                 return false;
673
674         printf("SV[P]\tprev\n");
675         if(!iterator.prev())
676                 return die_("iterator ended early\n");
677         our_current_position--;
678
679         printf("S[V]P\tprev\n");
680         if(!iterator.prev())
681                 return die_("iterator ended early\n");
682         our_current_position--;
683
684         printf("[S]VP\tset STREAMINFO (change sample rate)\n");
685         FLAC__ASSERT(our_current_position == 0);
686         block = iterator.get_block();
687         streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
688         FLAC__ASSERT(0 != streaminfo);
689         streaminfo->set_sample_rate(32000);
690         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
691                 return die_("copying object");
692         if(!iterator.set_block(block, false))
693                 return die_ss_("iterator.set_block(block, false)", iterator);
694         delete block;
695
696         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
697                 return false;
698
699         printf("[S]VP\tnext\n");
700         if(!iterator.next())
701                 return die_("iterator ended early\n");
702         our_current_position++;
703
704         printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
705         app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
706         if(!iterator.insert_block_after(app, true))
707                 return die_ss_("iterator.insert_block_after(app, true)", iterator);
708         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
709                 return false;
710         add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
711
712         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
713                 return false;
714
715         printf("SV[A]P\tnext\n");
716         if(!iterator.next())
717                 return die_("iterator ended early\n");
718         our_current_position++;
719
720         printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
721         app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
722         if(!iterator.set_block(app, true))
723                 return die_ss_("iterator.set_block(app, true)", iterator);
724         if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
725                 return false;
726         add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
727
728         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
729                 return false;
730
731         printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
732         app->set_id((const unsigned char *)"guh"); /* twiddle the id */
733         if(!app->set_data(data, sizeof(data), true))
734                 return die_("setting APPLICATION data");
735         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
736                 return die_("copying object");
737         if(!iterator.set_block(app, false))
738                 return die_ss_("iterator.set_block(app, false)", iterator);
739
740         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
741                 return false;
742
743         printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
744         app->set_id((const unsigned char *)"huh"); /* twiddle the id */
745         if(!app->set_data(data, 12, true))
746                 return die_("setting APPLICATION data");
747         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
748                 return die_("copying object");
749         if(!iterator.set_block(app, false))
750                 return die_ss_("iterator.set_block(app, false)", iterator);
751
752         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
753                 return false;
754
755         printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
756         app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
757         if(!app->set_data(data, sizeof(data), true))
758                 return die_("setting APPLICATION data");
759         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
760                 return die_("copying object");
761         add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
762         if(!iterator.set_block(app, true))
763                 return die_ss_("iterator.set_block(app, true)", iterator);
764
765         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
766                 return false;
767
768         printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
769         app->set_id((const unsigned char *)"juh"); /* twiddle the id */
770         if(!app->set_data(data, 23, true))
771                 return die_("setting APPLICATION data");
772         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
773                 return die_("copying object");
774         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
775                 return die_("copying object");
776         dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
777         if(!iterator.set_block(app, true))
778                 return die_ss_("iterator.set_block(app, true)", iterator);
779
780         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
781                 return false;
782
783         printf("SVA[A]PP\tnext\n");
784         if(!iterator.next())
785                 return die_("iterator ended early\n");
786         our_current_position++;
787
788         printf("SVAA[P]P\tnext\n");
789         if(!iterator.next())
790                 return die_("iterator ended early\n");
791         our_current_position++;
792
793         printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
794         padding->set_length(5);
795         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
796                 return die_("copying object");
797         if(!iterator.set_block(padding, false))
798                 return die_ss_("iterator.set_block(padding, false)", iterator);
799
800         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
801                 return false;
802
803         printf("SVAAP[P]\tset APPLICATION (grow)\n");
804         app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
805         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
806                 return die_("copying object");
807         if(!iterator.set_block(app, false))
808                 return die_ss_("iterator.set_block(app, false)", iterator);
809
810         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
811                 return false;
812
813         printf("SVAAP[A]\tset PADDING (equal)\n");
814         padding->set_length(27);
815         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
816                 return die_("copying object");
817         if(!iterator.set_block(padding, false))
818                 return die_ss_("iterator.set_block(padding, false)", iterator);
819
820         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
821                 return false;
822
823         printf("SVAAP[P]\tprev\n");
824         if(!iterator.prev())
825                 return die_("iterator ended early\n");
826         our_current_position--;
827
828         printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
829         if(!iterator.delete_block(false))
830                 return die_ss_("iterator.delete_block(false)", iterator);
831         delete_from_our_metadata_(our_current_position--);
832
833         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
834                 return false;
835
836         printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
837         if(!iterator.delete_block(false))
838                 return die_ss_("iterator.delete_block(false)", iterator);
839         delete_from_our_metadata_(our_current_position--);
840
841         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
842                 return false;
843
844         printf("SV[A]P\tnext\n");
845         if(!iterator.next())
846                 return die_("iterator ended early\n");
847         our_current_position++;
848
849         printf("SVA[P]\tinsert PADDING after\n");
850         padding->set_length(5);
851         if(!iterator.insert_block_after(padding, false))
852                 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
853         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
854                 return false;
855
856         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
857                 return false;
858
859         printf("SVAP[P]\tprev\n");
860         if(!iterator.prev())
861                 return die_("iterator ended early\n");
862         our_current_position--;
863
864         printf("SVA[P]P\tprev\n");
865         if(!iterator.prev())
866                 return die_("iterator ended early\n");
867         our_current_position--;
868
869         printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
870         if(!app->set_data(data, 32, true))
871                 return die_("setting APPLICATION data");
872         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
873                 return die_("copying object");
874         if(!iterator.set_block(app, true))
875                 return die_ss_("iterator.set_block(app, true)", iterator);
876
877         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
878                 return false;
879
880         printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
881         if(!app->set_data(data, 60, true))
882                 return die_("setting APPLICATION data");
883         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
884                 return die_("copying object");
885         if(!iterator.set_block(app, true))
886                 return die_ss_("iterator.set_block(app, true)", iterator);
887
888         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
889                 return false;
890
891         printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
892         if(!app->set_data(data, 87, true))
893                 return die_("setting APPLICATION data");
894         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
895                 return die_("copying object");
896         dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
897         if(!iterator.set_block(app, true))
898                 return die_ss_("iterator.set_block(app, true)", iterator);
899
900         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
901                 return false;
902
903         printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
904         if(!app->set_data(data, 91, true))
905                 return die_("setting APPLICATION data");
906         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
907                 return die_("copying object");
908         delete_from_our_metadata_(our_current_position+1);
909         if(!iterator.set_block(app, true))
910                 return die_ss_("iterator.set_block(app, true)", iterator);
911
912         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
913                 return false;
914
915         printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
916         if(!app->set_data(data, 100, true))
917                 return die_("setting APPLICATION data");
918         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
919                 return die_("copying object");
920         delete_from_our_metadata_(our_current_position+1);
921         our_metadata_.blocks[our_current_position]->set_is_last(true);
922         if(!iterator.set_block(app, true))
923                 return die_ss_("iterator.set_block(app, true)", iterator);
924
925         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
926                 return false;
927
928         printf("SV[A]\tset PADDING (equal size)\n");
929         padding->set_length(app->get_length());
930         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
931                 return die_("copying object");
932         if(!iterator.set_block(padding, true))
933                 return die_ss_("iterator.set_block(padding, true)", iterator);
934
935         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
936                 return false;
937
938         printf("SV[P]\tinsert PADDING after\n");
939         if(!iterator.insert_block_after(padding, false))
940                 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
941         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
942                 return false;
943
944         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
945                 return false;
946
947         printf("SVP[P]\tinsert PADDING after\n");
948         padding->set_length(5);
949         if(!iterator.insert_block_after(padding, false))
950                 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
951         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
952                 return false;
953
954         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
955                 return false;
956
957         printf("SVPP[P]\tprev\n");
958         if(!iterator.prev())
959                 return die_("iterator ended early\n");
960         our_current_position--;
961
962         printf("SVP[P]P\tprev\n");
963         if(!iterator.prev())
964                 return die_("iterator ended early\n");
965         our_current_position--;
966
967         printf("SV[P]PP\tprev\n");
968         if(!iterator.prev())
969                 return die_("iterator ended early\n");
970         our_current_position--;
971
972         printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
973         if(!app->set_data(data, 101, true))
974                 return die_("setting APPLICATION data");
975         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
976                 return die_("copying object");
977         if(!iterator.insert_block_after(app, true))
978                 return die_ss_("iterator.insert_block_after(app, true)", iterator);
979
980         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
981                 return false;
982
983         printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
984         if(!iterator.delete_block(false))
985                 return die_ss_("iterator.delete_block(false)", iterator);
986         delete_from_our_metadata_(our_current_position--);
987
988         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
989                 return false;
990
991         printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
992         if(!app->set_data(data, 97, true))
993                 return die_("setting APPLICATION data");
994         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
995                 return die_("copying object");
996         if(!iterator.insert_block_after(app, true))
997                 return die_ss_("iterator.insert_block_after(app, true)", iterator);
998
999         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1000                 return false;
1001
1002         printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1003         if(!iterator.delete_block(false))
1004                 return die_ss_("iterator.delete_block(false)", iterator);
1005         delete_from_our_metadata_(our_current_position--);
1006
1007         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1008                 return false;
1009
1010         printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1011         if(!app->set_data(data, 100, true))
1012                 return die_("setting APPLICATION data");
1013         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1014                 return die_("copying object");
1015         delete_from_our_metadata_(our_current_position+1);
1016         if(!iterator.insert_block_after(app, true))
1017                 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1018
1019         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1020                 return false;
1021
1022         printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1023         if(!iterator.delete_block(false))
1024                 return die_ss_("iterator.delete_block(false)", iterator);
1025         delete_from_our_metadata_(our_current_position--);
1026
1027         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1028                 return false;
1029
1030         printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1031         if(!app->set_data(data, 96, true))
1032                 return die_("setting APPLICATION data");
1033         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1034                 return die_("copying object");
1035         dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1036         if(!iterator.insert_block_after(app, true))
1037                 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1038
1039         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1040                 return false;
1041
1042         printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1043         if(!iterator.delete_block(false))
1044                 return die_ss_("iterator.delete_block(false)", iterator);
1045         delete_from_our_metadata_(our_current_position--);
1046
1047         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1048                 return false;
1049
1050         printf("S[V]PP\tnext\n");
1051         if(!iterator.next())
1052                 return die_("iterator ended early\n");
1053         our_current_position++;
1054
1055         printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1056         if(!iterator.delete_block(false))
1057                 return die_ss_("iterator.delete_block(false)", iterator);
1058         delete_from_our_metadata_(our_current_position--);
1059
1060         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1061                 return false;
1062
1063         printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1064         if(!app->set_data(data, 1, true))
1065                 return die_("setting APPLICATION data");
1066         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1067                 return die_("copying object");
1068         delete_from_our_metadata_(our_current_position+1);
1069         if(!iterator.insert_block_after(app, true))
1070                 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1071
1072         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1073                 return false;
1074         }
1075
1076         delete app;
1077         delete padding;
1078
1079         if(!remove_file_(flacfile_))
1080                 return false;
1081
1082         return true;
1083 }
1084
1085 static bool test_level_2_()
1086 {
1087         FLAC::Metadata::Prototype *block;
1088         FLAC::Metadata::StreamInfo *streaminfo;
1089         FLAC::Metadata::Application *app;
1090         FLAC::Metadata::Padding *padding;
1091         FLAC__byte data[2000];
1092         unsigned our_current_position;
1093
1094         // initialize 'data' to avoid Valgrind errors
1095         memset(data, 0, sizeof(data));
1096
1097         printf("\n\n++++++ testing level 2 interface\n");
1098
1099         printf("generate read-only file\n");
1100
1101         if(!generate_file_())
1102                 return false;
1103
1104         if(!change_stats_(flacfile_, /*read_only=*/true))
1105                 return false;
1106
1107         printf("create chain\n");
1108         FLAC::Metadata::Chain chain;
1109         if(!chain.is_valid())
1110                 return die_("allocating memory for chain");
1111
1112         printf("read chain\n");
1113
1114         if(!chain.read(flacfile_))
1115                 return die_c_("reading chain", chain.status());
1116
1117         printf("[S]VP\ttest initial metadata\n");
1118
1119         if(!compare_chain_(chain, 0, 0))
1120                 return false;
1121         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1122                 return false;
1123
1124         printf("switch file to read-write\n");
1125
1126         if(!change_stats_(flacfile_, /*read-only=*/false))
1127                 return false;
1128
1129         printf("create iterator\n");
1130         {
1131         FLAC::Metadata::Iterator iterator;
1132         if(!iterator.is_valid())
1133                 return die_("allocating memory for iterator");
1134
1135         our_current_position = 0;
1136
1137         iterator.init(chain);
1138
1139         if(0 == (block = iterator.get_block()))
1140                 return die_("getting block from iterator");
1141
1142         FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1143
1144         printf("[S]VP\tmodify STREAMINFO, write\n");
1145
1146         streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1147         FLAC__ASSERT(0 != streaminfo);
1148         streaminfo->set_sample_rate(32000);
1149         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1150                 return die_("copying object");
1151         delete block;
1152
1153         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/true))
1154                 return die_c_("during chain.write(false, true)", chain.status());
1155         block = iterator.get_block();
1156         if(!compare_chain_(chain, our_current_position, block))
1157                 return false;
1158         delete block;
1159         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1160                 return false;
1161
1162         printf("[S]VP\tnext\n");
1163         if(!iterator.next())
1164                 return die_("iterator ended early\n");
1165         our_current_position++;
1166
1167         printf("S[V]P\tnext\n");
1168         if(!iterator.next())
1169                 return die_("iterator ended early\n");
1170         our_current_position++;
1171
1172         printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1173         if(0 == (block = iterator.get_block()))
1174                 return die_("getting block from iterator");
1175         if(0 == (app = new FLAC::Metadata::Application()))
1176                 return die_("new FLAC::Metadata::Application()");
1177         app->set_id((const unsigned char *)"duh");
1178         if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1179                 return die_("setting APPLICATION data");
1180         delete block;
1181         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1182                 return die_("copying object");
1183         if(!iterator.set_block(app))
1184                 return die_c_("iterator.set_block(app)", chain.status());
1185
1186         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1187                 return die_c_("during chain.write(false, false)", chain.status());
1188         block = iterator.get_block();
1189         if(!compare_chain_(chain, our_current_position, block))
1190                 return false;
1191         delete block;
1192         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1193                 return false;
1194
1195         printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1196         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1197                 return die_("copying object");
1198         if(!app->set_data(data, 26, true))
1199                 return die_("setting APPLICATION data");
1200         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1201                 return die_("copying object");
1202         if(!iterator.set_block(app))
1203                 return die_c_("iterator.set_block(app)", chain.status());
1204
1205         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1206                 return die_c_("during chain.write(false, false)", chain.status());
1207         block = iterator.get_block();
1208         if(!compare_chain_(chain, our_current_position, block))
1209                 return false;
1210         delete block;
1211         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1212                 return false;
1213
1214         printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1215         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1216                 return die_("copying object");
1217         if(!app->set_data(data, 28, true))
1218                 return die_("setting APPLICATION data");
1219         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1220                 return die_("copying object");
1221         if(!iterator.set_block(app))
1222                 return die_c_("iterator.set_block(app)", chain.status());
1223
1224         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1225                 return die_c_("during chain.write(false, false)", chain.status());
1226         block = iterator.get_block();
1227         if(!compare_chain_(chain, our_current_position, block))
1228                 return false;
1229         delete block;
1230         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1231                 return false;
1232
1233         printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1234         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1235                 return die_("copying object");
1236         if(!app->set_data(data, 36, true))
1237                 return die_("setting APPLICATION data");
1238         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1239                 return die_("copying object");
1240         if(!iterator.set_block(app))
1241                 return die_c_("iterator.set_block(app)", chain.status());
1242
1243         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1244                 return die_c_("during chain.write(false, false)", chain.status());
1245         block = iterator.get_block();
1246         if(!compare_chain_(chain, our_current_position, block))
1247                 return false;
1248         delete block;
1249         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1250                 return false;
1251
1252         printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1253         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1254                 return die_("copying object");
1255         if(!app->set_data(data, 33, true))
1256                 return die_("setting APPLICATION data");
1257         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1258                 return die_("copying object");
1259         if(!iterator.set_block(app))
1260                 return die_c_("iterator.set_block(app)", chain.status());
1261
1262         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1263                 return die_c_("during chain.write(true, false)", chain.status());
1264         block = iterator.get_block();
1265         if(!compare_chain_(chain, our_current_position, block))
1266                 return false;
1267         delete block;
1268         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1269                 return false;
1270
1271         printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1272         if(0 == (padding = new FLAC::Metadata::Padding()))
1273                 return die_("creating PADDING block");
1274         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1275                 return die_("copying object");
1276         if(!app->set_data(data, 29, true))
1277                 return die_("setting APPLICATION data");
1278         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1279                 return die_("copying object");
1280         padding->set_length(0);
1281         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1282                 return die_("internal error");
1283         if(!iterator.set_block(app))
1284                 return die_c_("iterator.set_block(app)", chain.status());
1285
1286         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1287                 return die_c_("during chain.write(true, false)", chain.status());
1288         block = iterator.get_block();
1289         if(!compare_chain_(chain, our_current_position, block))
1290                 return false;
1291         delete block;
1292         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1293                 return false;
1294
1295         printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1296         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1297                 return die_("copying object");
1298         if(!app->set_data(data, 16, true))
1299                 return die_("setting APPLICATION data");
1300         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1301                 return die_("copying object");
1302         dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1303         if(!iterator.set_block(app))
1304                 return die_c_("iterator.set_block(app)", chain.status());
1305
1306         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1307                 return die_c_("during chain.write(true, false)", chain.status());
1308         block = iterator.get_block();
1309         if(!compare_chain_(chain, our_current_position, block))
1310                 return false;
1311         delete block;
1312         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1313                 return false;
1314
1315         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1316         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1317                 return die_("copying object");
1318         if(!app->set_data(data, 50, true))
1319                 return die_("setting APPLICATION data");
1320         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1321                 return die_("copying object");
1322         if(!iterator.set_block(app))
1323                 return die_c_("iterator.set_block(app)", chain.status());
1324
1325         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1326                 return die_c_("during chain.write(true, false)", chain.status());
1327         block = iterator.get_block();
1328         if(!compare_chain_(chain, our_current_position, block))
1329                 return false;
1330         delete block;
1331         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1332                 return false;
1333
1334         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1335         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1336                 return die_("copying object");
1337         if(!app->set_data(data, 56, true))
1338                 return die_("setting APPLICATION data");
1339         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1340                 return die_("copying object");
1341         add_to_padding_length_(our_current_position+1, -(56 - 50));
1342         if(!iterator.set_block(app))
1343                 return die_c_("iterator.set_block(app)", chain.status());
1344
1345         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1346                 return die_c_("during chain.write(true, false)", chain.status());
1347         block = iterator.get_block();
1348         if(!compare_chain_(chain, our_current_position, block))
1349                 return false;
1350         delete block;
1351         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1352                 return false;
1353
1354         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1355         if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1356                 return die_("copying object");
1357         if(!app->set_data(data, 67, true))
1358                 return die_("setting APPLICATION data");
1359         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1360                 return die_("copying object");
1361         delete_from_our_metadata_(our_current_position+1);
1362         if(!iterator.set_block(app))
1363                 return die_c_("iterator.set_block(app)", chain.status());
1364
1365         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1366                 return die_c_("during chain.write(true, false)", chain.status());
1367         block = iterator.get_block();
1368         if(!compare_chain_(chain, our_current_position, block))
1369                 return false;
1370         delete block;
1371         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1372                 return false;
1373
1374         printf("SV[A]\tprev\n");
1375         if(!iterator.prev())
1376                 return die_("iterator ended early\n");
1377         our_current_position--;
1378
1379         printf("S[V]A\tprev\n");
1380         if(!iterator.prev())
1381                 return die_("iterator ended early\n");
1382         our_current_position--;
1383
1384         printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1385         if(0 == (padding = new FLAC::Metadata::Padding()))
1386                 return die_("creating PADDING block");
1387         padding->set_length(30);
1388         if(!iterator.insert_block_before(padding))
1389                 printf("\titerator.insert_block_before() returned false like it should\n");
1390         else
1391                 return die_("iterator.insert_block_before() should have returned false");
1392
1393         printf("[S]VA\tnext\n");
1394         if(!iterator.next())
1395                 return die_("iterator ended early\n");
1396         our_current_position++;
1397
1398         printf("S[V]A\tinsert PADDING after\n");
1399         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1400                 return die_("copying metadata");
1401         if(!iterator.insert_block_after(padding))
1402                 return die_("iterator.insert_block_after(padding)");
1403
1404         block = iterator.get_block();
1405         if(!compare_chain_(chain, our_current_position, block))
1406                 return false;
1407         delete block;
1408
1409         printf("SV[P]A\tinsert PADDING before\n");
1410         if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1411                 return die_("creating PADDING block");
1412         padding->set_length(17);
1413         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1414                 return die_("copying metadata");
1415         if(!iterator.insert_block_before(padding))
1416                 return die_("iterator.insert_block_before(padding)");
1417
1418         block = iterator.get_block();
1419         if(!compare_chain_(chain, our_current_position, block))
1420                 return false;
1421         delete block;
1422
1423         printf("SV[P]PA\tinsert PADDING before\n");
1424         if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1425                 return die_("creating PADDING block");
1426         padding->set_length(0);
1427         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1428                 return die_("copying metadata");
1429         if(!iterator.insert_block_before(padding))
1430                 return die_("iterator.insert_block_before(padding)");
1431
1432         block = iterator.get_block();
1433         if(!compare_chain_(chain, our_current_position, block))
1434                 return false;
1435         delete block;
1436
1437         printf("SV[P]PPA\tnext\n");
1438         if(!iterator.next())
1439                 return die_("iterator ended early\n");
1440         our_current_position++;
1441
1442         printf("SVP[P]PA\tnext\n");
1443         if(!iterator.next())
1444                 return die_("iterator ended early\n");
1445         our_current_position++;
1446
1447         printf("SVPP[P]A\tnext\n");
1448         if(!iterator.next())
1449                 return die_("iterator ended early\n");
1450         our_current_position++;
1451
1452         printf("SVPPP[A]\tinsert PADDING after\n");
1453         if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1454                 return die_("creating PADDING block");
1455         padding->set_length(57);
1456         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1457                 return die_("copying metadata");
1458         if(!iterator.insert_block_after(padding))
1459                 return die_("iterator.insert_block_after(padding)");
1460
1461         block = iterator.get_block();
1462         if(!compare_chain_(chain, our_current_position, block))
1463                 return false;
1464         delete block;
1465
1466         printf("SVPPPA[P]\tinsert PADDING before\n");
1467         if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1468                 return die_("creating PADDING block");
1469         padding->set_length(99);
1470         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1471                 return die_("copying metadata");
1472         if(!iterator.insert_block_before(padding))
1473                 return die_("iterator.insert_block_before(padding)");
1474
1475         block = iterator.get_block();
1476         if(!compare_chain_(chain, our_current_position, block))
1477                 return false;
1478         delete block;
1479
1480         }
1481         our_current_position = 0;
1482
1483         printf("SVPPPAPP\tmerge padding\n");
1484         chain.merge_padding();
1485         add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1486         add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1487         add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1488         delete_from_our_metadata_(7);
1489         delete_from_our_metadata_(4);
1490         delete_from_our_metadata_(3);
1491
1492         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1493                 return die_c_("during chain.write(true, false)", chain.status());
1494         if(!compare_chain_(chain, 0, 0))
1495                 return false;
1496         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1497                 return false;
1498
1499         printf("SVPAP\tsort padding\n");
1500         chain.sort_padding();
1501         add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1502         delete_from_our_metadata_(2);
1503
1504         if(!chain.write(/*use_padding=*/true, /*preserve_file_stats=*/false))
1505                 return die_c_("during chain.write(true, false)", chain.status());
1506         if(!compare_chain_(chain, 0, 0))
1507                 return false;
1508         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1509                 return false;
1510
1511         printf("create iterator\n");
1512         {
1513         FLAC::Metadata::Iterator iterator;
1514         if(!iterator.is_valid())
1515                 return die_("allocating memory for iterator");
1516
1517         our_current_position = 0;
1518
1519         iterator.init(chain);
1520
1521         printf("[S]VAP\tnext\n");
1522         if(!iterator.next())
1523                 return die_("iterator ended early\n");
1524         our_current_position++;
1525
1526         printf("S[V]AP\tnext\n");
1527         if(!iterator.next())
1528                 return die_("iterator ended early\n");
1529         our_current_position++;
1530
1531         printf("SV[A]P\tdelete middle block, replace with padding\n");
1532         if(0 == (padding = new FLAC::Metadata::Padding()))
1533                 return die_("creating PADDING block");
1534         padding->set_length(71);
1535         if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1536                 return die_("copying object");
1537         if(!iterator.delete_block(/*replace_with_padding=*/true))
1538                 return die_c_("iterator.delete_block(true)", chain.status());
1539
1540         block = iterator.get_block();
1541         if(!compare_chain_(chain, our_current_position, block))
1542                 return false;
1543         delete block;
1544
1545         printf("S[V]PP\tnext\n");
1546         if(!iterator.next())
1547                 return die_("iterator ended early\n");
1548         our_current_position++;
1549
1550         printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1551         delete_from_our_metadata_(our_current_position--);
1552         if(!iterator.delete_block(/*replace_with_padding=*/false))
1553                 return die_c_("iterator.delete_block(false)", chain.status());
1554
1555         block = iterator.get_block();
1556         if(!compare_chain_(chain, our_current_position, block))
1557                 return false;
1558         delete block;
1559
1560         printf("S[V]P\tnext\n");
1561         if(!iterator.next())
1562                 return die_("iterator ended early\n");
1563         our_current_position++;
1564
1565         printf("SV[P]\tdelete last block, replace with padding\n");
1566         if(0 == (padding = new FLAC::Metadata::Padding()))
1567                 return die_("creating PADDING block");
1568         padding->set_length(219);
1569         if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1570                 return die_("copying object");
1571         if(!iterator.delete_block(/*replace_with_padding=*/true))
1572                 return die_c_("iterator.delete_block(true)", chain.status());
1573
1574         block = iterator.get_block();
1575         if(!compare_chain_(chain, our_current_position, block))
1576                 return false;
1577         delete block;
1578
1579         printf("S[V]P\tnext\n");
1580         if(!iterator.next())
1581                 return die_("iterator ended early\n");
1582         our_current_position++;
1583
1584         printf("SV[P]\tdelete last block, don't replace with padding\n");
1585         delete_from_our_metadata_(our_current_position--);
1586         if(!iterator.delete_block(/*replace_with_padding=*/false))
1587                 return die_c_("iterator.delete_block(false)", chain.status());
1588
1589         block = iterator.get_block();
1590         if(!compare_chain_(chain, our_current_position, block))
1591                 return false;
1592         delete block;
1593
1594         printf("S[V]\tprev\n");
1595         if(!iterator.prev())
1596                 return die_("iterator ended early\n");
1597         our_current_position--;
1598
1599         printf("[S]V\tdelete STREAMINFO block, should fail\n");
1600         if(iterator.delete_block(/*replace_with_padding=*/false))
1601                 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1602
1603         block = iterator.get_block();
1604         if(!compare_chain_(chain, our_current_position, block))
1605                 return false;
1606         delete block;
1607
1608         }
1609         our_current_position = 0;
1610
1611         printf("SV\tmerge padding\n");
1612         chain.merge_padding();
1613
1614         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1615                 return die_c_("during chain.write(false, false)", chain.status());
1616         if(!compare_chain_(chain, 0, 0))
1617                 return false;
1618         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1619                 return false;
1620
1621         printf("SV\tsort padding\n");
1622         chain.sort_padding();
1623
1624         if(!chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
1625                 return die_c_("during chain.write(false, false)", chain.status());
1626         if(!compare_chain_(chain, 0, 0))
1627                 return false;
1628         if(!test_file_(flacfile_, /*ignore_metadata=*/false))
1629                 return false;
1630
1631         if(!remove_file_(flacfile_))
1632                 return false;
1633
1634         return true;
1635 }
1636
1637 bool test_metadata_file_manipulation()
1638 {
1639         printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
1640
1641         our_metadata_.num_blocks = 0;
1642
1643         if(!test_level_0_())
1644                 return false;
1645
1646         if(!test_level_1_())
1647                 return false;
1648
1649         if(!test_level_2_())
1650                 return false;
1651
1652         return true;
1653 }