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