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