add tests for callback-based chain reading/writing
[platform/upstream/flac.git] / src / test_libFLAC / metadata_manip.c
1 /* test_libFLAC - Unit tester for libFLAC
2  * Copyright (C) 2002,2003,2004  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 #include "file_utils.h"
20 #include "metadata_utils.h"
21 #include "FLAC/assert.h"
22 #include "FLAC/file_decoder.h"
23 #include "FLAC/metadata.h"
24 #include "share/grabbag.h"
25 #include <stdio.h>
26 #include <stdlib.h> /* for malloc() */
27
28 #if defined _MSC_VER || defined __MINGW32__
29 #include <sys/utime.h> /* for utime() */
30 #include <io.h> /* for chmod() */
31 #else
32 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
33 #include <utime.h> /* for utime() */
34 #include <unistd.h> /* for chown(), unlink() */
35 #endif
36 #include <sys/stat.h> /* for stat(), maybe chmod() */
37
38
39 /******************************************************************************
40         The general strategy of these tests (for interface levels 1 and 2) is
41         to create a dummy FLAC file with a known set of initial metadata
42         blocks, then keep a mirror locally of what we expect the metadata to be
43         after each operation.  Then testing becomes a simple matter of running
44         a FLAC__FileDecoder over the dummy file after each operation, comparing
45         the decoded metadata to what's in our local copy.  If there are any
46         differences in the metadata, or the actual audio data is corrupted, we
47         will catch it while decoding.
48 ******************************************************************************/
49
50 typedef struct {
51         FLAC__bool error_occurred;
52 } decoder_client_struct;
53
54 typedef struct {
55         FLAC__StreamMetadata *blocks[64];
56         unsigned num_blocks;
57 } our_metadata_struct;
58
59 static const char *flacfile_ = "metadata.flac";
60
61 /* our copy of the metadata in flacfile_ */
62 static our_metadata_struct our_metadata_;
63
64 /* the current block number that corresponds to the position of the iterator we are testing */
65 static unsigned mc_our_block_number_ = 0;
66
67 static FLAC__bool die_(const char *msg)
68 {
69         printf("ERROR: %s\n", msg);
70         return false;
71 }
72
73 static FLAC__bool die_c_(const char *msg, FLAC__Metadata_ChainStatus status)
74 {
75         printf("ERROR: %s\n", msg);
76         printf("       status=%s\n", FLAC__Metadata_ChainStatusString[status]);
77         return false;
78 }
79
80 static FLAC__bool die_ss_(const char *msg, FLAC__Metadata_SimpleIterator *iterator)
81 {
82         printf("ERROR: %s\n", msg);
83         printf("       status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]);
84         return false;
85 }
86
87 static void *malloc_or_die_(size_t size)
88 {
89         void *x = malloc(size);
90         if(0 == x) {
91                 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
92                 exit(1);
93         }
94         return x;
95 }
96
97 /* functions for working with our metadata copy */
98
99 static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
100 {
101         unsigned i;
102         FLAC__StreamMetadata *obj = block;
103         FLAC__ASSERT(position < our_metadata_.num_blocks);
104         if(copy) {
105                 if(0 == (obj = FLAC__metadata_object_clone(block)))
106                         return die_("during FLAC__metadata_object_clone()");
107         }
108         FLAC__metadata_object_delete(our_metadata_.blocks[position]);
109         our_metadata_.blocks[position] = obj;
110
111         /* set the is_last flags */
112         for(i = 0; i < our_metadata_.num_blocks - 1; i++)
113                 our_metadata_.blocks[i]->is_last = false;
114         our_metadata_.blocks[i]->is_last = true;
115
116         return true;
117 }
118
119 static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
120 {
121         unsigned i;
122         FLAC__StreamMetadata *obj = block;
123         if(copy) {
124                 if(0 == (obj = FLAC__metadata_object_clone(block)))
125                         return die_("during FLAC__metadata_object_clone()");
126         }
127         if(position > our_metadata_.num_blocks) {
128                 position = our_metadata_.num_blocks;
129         }
130         else {
131                 for(i = our_metadata_.num_blocks; i > position; i--)
132                         our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
133         }
134         our_metadata_.blocks[position] = obj;
135         our_metadata_.num_blocks++;
136
137         /* set the is_last flags */
138         for(i = 0; i < our_metadata_.num_blocks - 1; i++)
139                 our_metadata_.blocks[i]->is_last = false;
140         our_metadata_.blocks[i]->is_last = true;
141
142         return true;
143 }
144
145 static void delete_from_our_metadata_(unsigned position)
146 {
147         unsigned i;
148         FLAC__ASSERT(position < our_metadata_.num_blocks);
149         FLAC__metadata_object_delete(our_metadata_.blocks[position]);
150         for(i = position; i < our_metadata_.num_blocks - 1; i++)
151                 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
152         our_metadata_.num_blocks--;
153
154         /* set the is_last flags */
155         if(our_metadata_.num_blocks > 0) {
156                 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
157                         our_metadata_.blocks[i]->is_last = false;
158                 our_metadata_.blocks[i]->is_last = true;
159         }
160 }
161
162 /*
163  * This wad of functions supports filename- and callback-based chain writing.
164  * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
165  */
166 FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
167 {
168         static const char *tempfile_suffix = ".metadata_edit";
169
170         if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
171                 return false;
172         strcpy(*tempfilename, filename);
173         strcat(*tempfilename, tempfile_suffix);
174
175         if(0 == (*tempfile = fopen(*tempfilename, "w+b")))
176                 return false;
177
178         return true;
179 }
180
181 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
182 {
183         if(0 != *tempfile) {
184                 (void)fclose(*tempfile);
185                 *tempfile = 0;
186         }
187
188         if(0 != *tempfilename) {
189                 (void)unlink(*tempfilename);
190                 free(*tempfilename);
191                 *tempfilename = 0;
192         }
193 }
194
195 FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
196 {
197         FLAC__ASSERT(0 != filename);
198         FLAC__ASSERT(0 != tempfile);
199         FLAC__ASSERT(0 != tempfilename);
200         FLAC__ASSERT(0 != *tempfilename);
201
202         if(0 != *tempfile) {
203                 (void)fclose(*tempfile);
204                 *tempfile = 0;
205         }
206
207 #if defined _MSC_VER || defined __MINGW32__
208         if(unlink(filename) < 0) {
209                 cleanup_tempfile_(tempfile, tempfilename);
210                 return false;
211         }
212 #endif
213
214         if(0 != rename(*tempfilename, filename)) {
215                 cleanup_tempfile_(tempfile, tempfilename);
216                 return false;
217         }
218
219         cleanup_tempfile_(tempfile, tempfilename);
220
221         return true;
222 }
223
224 FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
225 {
226         FLAC__ASSERT(0 != filename);
227         FLAC__ASSERT(0 != stats);
228         return (0 == stat(filename, stats));
229 }
230
231 void set_file_stats_(const char *filename, struct stat *stats)
232 {
233         struct utimbuf srctime;
234
235         FLAC__ASSERT(0 != filename);
236         FLAC__ASSERT(0 != stats);
237
238         srctime.actime = stats->st_atime;
239         srctime.modtime = stats->st_mtime;
240         (void)chmod(filename, stats->st_mode);
241         (void)utime(filename, &srctime);
242 #if !defined _MSC_VER && !defined __MINGW32__
243         (void)chown(filename, stats->st_uid, -1);
244         (void)chown(filename, -1, stats->st_gid);
245 #endif
246 }
247
248 #ifdef FLAC__VALGRIND_TESTING
249 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
250 {
251         FILE *stream = (FILE*)handle;
252         size_t ret = fwrite(ptr, size, nmemb, stream);
253         if(!ferror(stream))
254                 fflush(stream);
255         return ret;
256 }
257 #endif
258
259 static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
260 {
261         long o = (long)offset;
262         FLAC__ASSERT(offset == o);
263         return fseek((FILE*)handle, o, whence);
264 }
265
266 static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle)
267 {
268         return ftell((FILE*)handle);
269 }
270
271 static int chain_eof_cb_(FLAC__IOHandle handle)
272 {
273         return feof((FILE*)handle);
274 }
275
276 static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename)
277 {
278         if(filename_based)
279                 return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats);
280         else {
281                 FLAC__IOCallbacks callbacks;
282
283                 memset(&callbacks, 0, sizeof(callbacks));
284                 callbacks.read = (FLAC__IOCallback_Read)fread;
285 #ifdef FLAC__VALGRIND_TESTING
286                 callbacks.write = chain_write_cb_;
287 #else
288                 callbacks.write = (FLAC__IOCallback_Write)fwrite;
289 #endif
290                 callbacks.seek = chain_seek_cb_;
291                 callbacks.eof = chain_eof_cb_;
292                 callbacks.close = (FLAC__IOCallback_Close)fclose;
293
294                 if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
295                         struct stat stats;
296                         FILE *file, *tempfile;
297                         char *tempfilename;
298                         if(preserve_file_stats) {
299                                 if(!get_file_stats_(filename, &stats))
300                                         return false;
301                         }
302                         if(0 == (file = fopen(filename, "rb")))
303                                 return false; /*@@@ chain status still says OK though */
304                         if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
305                                 fclose(file);
306                                 cleanup_tempfile_(&tempfile, &tempfilename);
307                                 return false; /*@@@ chain status still says OK though */
308                         }
309                         if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks))
310                                 return false;
311                         file = tempfile = 0; /* FLAC__metadata_chain_write_with_callbacks_and_tempfile() always closes the file handles */
312                         if(!transport_tempfile_(filename, &tempfile, &tempfilename))
313                                 return false;
314                         if(preserve_file_stats)
315                                 set_file_stats_(filename, &stats);
316                 }
317                 else {
318                         FILE *file = fopen(filename, "r+b");
319                         if(0 == file)
320                                 return false; /*@@@ chain status still says OK though */
321                         if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks))
322                                 return false;
323                 }
324         }
325
326         return true;
327 }
328
329 static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based)
330 {
331         if(filename_based)
332                 return FLAC__metadata_chain_read(chain, flacfile_);
333         else {
334                 FLAC__IOCallbacks callbacks;
335
336                 memset(&callbacks, 0, sizeof(callbacks));
337                 callbacks.read = (FLAC__IOCallback_Read)fread;
338                 callbacks.seek = chain_seek_cb_;
339                 callbacks.tell = chain_tell_cb_;
340                 callbacks.close = (FLAC__IOCallback_Close)fclose;
341
342                 {
343                         FILE *file = fopen(filename, "rb");
344                         if(0 == file)
345                                 return false; /*@@@ chain status still says OK though */
346                         return FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks);
347                 }
348         }
349 }
350
351 /* function for comparing our metadata to a FLAC__Metadata_Chain */
352
353 static FLAC__bool compare_chain_(FLAC__Metadata_Chain *chain, unsigned current_position, FLAC__StreamMetadata *current_block)
354 {
355         unsigned i;
356         FLAC__Metadata_Iterator *iterator;
357         FLAC__StreamMetadata *block;
358         FLAC__bool next_ok = true;
359
360         FLAC__ASSERT(0 != chain);
361
362         printf("\tcomparing chain... ");
363         fflush(stdout);
364
365         if(0 == (iterator = FLAC__metadata_iterator_new()))
366                 return die_("allocating memory for iterator");
367
368         FLAC__metadata_iterator_init(iterator, chain);
369
370         i = 0;
371         do {
372                 printf("%u... ", i);
373                 fflush(stdout);
374
375                 if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
376                         FLAC__metadata_iterator_delete(iterator);
377                         return die_("getting block from iterator");
378                 }
379
380                 if(!mutils__compare_block(our_metadata_.blocks[i], block)) {
381                         FLAC__metadata_iterator_delete(iterator);
382                         return die_("metadata block mismatch");
383                 }
384
385                 i++;
386                 next_ok = FLAC__metadata_iterator_next(iterator);
387         } while(i < our_metadata_.num_blocks && next_ok);
388
389         FLAC__metadata_iterator_delete(iterator);
390
391         if(next_ok)
392                 return die_("chain has more blocks than expected");
393
394         if(i < our_metadata_.num_blocks)
395                 return die_("short block count in chain");
396
397         if(0 != current_block) {
398                 printf("CURRENT_POSITION... ");
399                 fflush(stdout);
400
401                 if(!mutils__compare_block(our_metadata_.blocks[current_position], current_block))
402                         return die_("metadata block mismatch");
403         }
404
405         printf("PASSED\n");
406
407         return true;
408 }
409
410 /* decoder callbacks for checking the file */
411
412 static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
413 {
414         (void)decoder, (void)buffer, (void)client_data;
415
416         if(
417                 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
418                 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
419         ) {
420                 printf("content... ");
421                 fflush(stdout);
422         }
423
424         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
425 }
426
427 /* this version pays no attention to the metadata */
428 static void decoder_metadata_callback_null_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
429 {
430         (void)decoder, (void)metadata, (void)client_data;
431
432         printf("%d... ", mc_our_block_number_);
433         fflush(stdout);
434
435         mc_our_block_number_++;
436 }
437
438 /* this version is used when we want to compare to our metadata copy */
439 static void decoder_metadata_callback_compare_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
440 {
441         decoder_client_struct *dcd = (decoder_client_struct*)client_data;
442
443         (void)decoder;
444
445         /* don't bother checking if we've already hit an error */
446         if(dcd->error_occurred)
447                 return;
448
449         printf("%d... ", mc_our_block_number_);
450         fflush(stdout);
451
452         if(mc_our_block_number_ >= our_metadata_.num_blocks) {
453                 (void)die_("got more metadata blocks than expected");
454                 dcd->error_occurred = true;
455         }
456         else {
457                 if(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) {
458                         (void)die_("metadata block mismatch");
459                         dcd->error_occurred = true;
460                 }
461         }
462         mc_our_block_number_++;
463 }
464
465 static void decoder_error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
466 {
467         decoder_client_struct *dcd = (decoder_client_struct*)client_data;
468         (void)decoder;
469
470         dcd->error_occurred = true;
471         printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
472 }
473
474 static FLAC__bool generate_file_()
475 {
476         FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
477         FLAC__StreamMetadata *metadata[1];
478
479         printf("generating FLAC file for test\n");
480
481         while(our_metadata_.num_blocks > 0)
482                 delete_from_our_metadata_(0);
483
484         streaminfo.is_last = false;
485         streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
486         streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
487         streaminfo.data.stream_info.min_blocksize = 576;
488         streaminfo.data.stream_info.max_blocksize = 576;
489         streaminfo.data.stream_info.min_framesize = 0;
490         streaminfo.data.stream_info.max_framesize = 0;
491         streaminfo.data.stream_info.sample_rate = 44100;
492         streaminfo.data.stream_info.channels = 1;
493         streaminfo.data.stream_info.bits_per_sample = 8;
494         streaminfo.data.stream_info.total_samples = 0;
495         memset(streaminfo.data.stream_info.md5sum, 0, 16);
496
497         {
498                 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
499                 vorbiscomment.is_last = false;
500                 vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
501                 vorbiscomment.length = (4 + vendor_string_length) + 4;
502                 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
503                 vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length);
504                 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
505                 vorbiscomment.data.vorbis_comment.num_comments = 0;
506                 vorbiscomment.data.vorbis_comment.comments = 0;
507         }
508
509         padding.is_last = true;
510         padding.type = FLAC__METADATA_TYPE_PADDING;
511         padding.length = 1234;
512
513         metadata[0] = &padding;
514
515         if(
516                 !insert_to_our_metadata_(&streaminfo, 0, /*copy=*/true) ||
517                 !insert_to_our_metadata_(&vorbiscomment, 1, /*copy=*/true) ||
518                 !insert_to_our_metadata_(&padding, 2, /*copy=*/true)
519         )
520                 return die_("priming our metadata");
521
522         if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
523                 return die_("creating the encoded file");
524
525         free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
526
527         return true;
528 }
529
530 static FLAC__bool test_file_(const char *filename, FLAC__FileDecoderMetadataCallback metadata_callback)
531 {
532         FLAC__FileDecoder *decoder;
533         decoder_client_struct decoder_client_data;
534
535         FLAC__ASSERT(0 != filename);
536         FLAC__ASSERT(0 != metadata_callback);
537
538         mc_our_block_number_ = 0;
539         decoder_client_data.error_occurred = false;
540
541         printf("\ttesting '%s'... ", filename);
542         fflush(stdout);
543
544         if(0 == (decoder = FLAC__file_decoder_new()))
545                 return die_("couldn't allocate decoder instance");
546
547         FLAC__file_decoder_set_md5_checking(decoder, true);
548         FLAC__file_decoder_set_filename(decoder, filename);
549         FLAC__file_decoder_set_write_callback(decoder, decoder_write_callback_);
550         FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
551         FLAC__file_decoder_set_error_callback(decoder, decoder_error_callback_);
552         FLAC__file_decoder_set_client_data(decoder, &decoder_client_data);
553         FLAC__file_decoder_set_metadata_respond_all(decoder);
554         if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
555                 FLAC__file_decoder_finish(decoder);
556                 FLAC__file_decoder_delete(decoder);
557                 return die_("initializing decoder\n");
558         }
559         if(!FLAC__file_decoder_process_until_end_of_file(decoder)) {
560                 FLAC__file_decoder_finish(decoder);
561                 FLAC__file_decoder_delete(decoder);
562                 return die_("decoding file\n");
563         }
564
565         FLAC__file_decoder_finish(decoder);
566         FLAC__file_decoder_delete(decoder);
567
568         if(decoder_client_data.error_occurred)
569                 return false;
570
571         if(mc_our_block_number_ != our_metadata_.num_blocks)
572                 return die_("short metadata block count");
573
574         printf("PASSED\n");
575         return true;
576 }
577
578 static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
579 {
580         if(!grabbag__file_change_stats(filename, read_only))
581                 return die_("during grabbag__file_change_stats()");
582
583         return true;
584 }
585
586 static FLAC__bool remove_file_(const char *filename)
587 {
588         while(our_metadata_.num_blocks > 0)
589                 delete_from_our_metadata_(0);
590
591         if(!grabbag__file_remove_file(filename))
592                 return die_("removing file");
593
594         return true;
595 }
596
597 static FLAC__bool test_level_0_()
598 {
599         FLAC__StreamMetadata streaminfo;
600
601         printf("\n\n++++++ testing level 0 interface\n");
602
603         if(!generate_file_())
604                 return false;
605
606         if(!test_file_(flacfile_, decoder_metadata_callback_null_))
607                 return false;
608
609         if(!FLAC__metadata_get_streaminfo(flacfile_, &streaminfo))
610                 return die_("during FLAC__metadata_get_streaminfo()");
611
612         /* check to see if some basic data matches (c.f. generate_file_()) */
613         if(streaminfo.data.stream_info.channels != 1)
614                 return die_("mismatch in streaminfo.data.stream_info.channels");
615         if(streaminfo.data.stream_info.bits_per_sample != 8)
616                 return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
617         if(streaminfo.data.stream_info.sample_rate != 44100)
618                 return die_("mismatch in streaminfo.data.stream_info.sample_rate");
619         if(streaminfo.data.stream_info.min_blocksize != 576)
620                 return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
621         if(streaminfo.data.stream_info.max_blocksize != 576)
622                 return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
623
624         if(!remove_file_(flacfile_))
625                 return false;
626
627         return true;
628 }
629
630 static FLAC__bool test_level_1_()
631 {
632         FLAC__Metadata_SimpleIterator *iterator;
633         FLAC__StreamMetadata *block, *app, *padding;
634         FLAC__byte data[1000];
635         unsigned our_current_position = 0;
636
637         /* initialize 'data' to avoid Valgrind errors */
638         memset(data, 0, sizeof(data));
639
640         printf("\n\n++++++ testing level 1 interface\n");
641
642         /************************************************************/
643
644         printf("simple iterator on read-only file\n");
645
646         if(!generate_file_())
647                 return false;
648
649         if(!change_stats_(flacfile_, /*read_only=*/true))
650                 return false;
651
652         if(!test_file_(flacfile_, decoder_metadata_callback_null_))
653                 return false;
654
655         if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
656                 return die_("FLAC__metadata_simple_iterator_new()");
657
658         if(!FLAC__metadata_simple_iterator_init(iterator, flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
659                 return die_("FLAC__metadata_simple_iterator_init() returned false");
660
661         printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
662         if(FLAC__metadata_simple_iterator_is_writable(iterator))
663                 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
664
665         printf("iterate forwards\n");
666
667         if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO)
668                 return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
669         if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
670                 return die_("getting block 0");
671         if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
672                 return die_("expected STREAMINFO type");
673         if(block->is_last)
674                 return die_("expected is_last to be false");
675         if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
676                 return die_("bad STREAMINFO length");
677         /* check to see if some basic data matches (c.f. generate_file_()) */
678         if(block->data.stream_info.channels != 1)
679                 return die_("mismatch in channels");
680         if(block->data.stream_info.bits_per_sample != 8)
681                 return die_("mismatch in bits_per_sample");
682         if(block->data.stream_info.sample_rate != 44100)
683                 return die_("mismatch in sample_rate");
684         if(block->data.stream_info.min_blocksize != 576)
685                 return die_("mismatch in min_blocksize");
686         if(block->data.stream_info.max_blocksize != 576)
687                 return die_("mismatch in max_blocksize");
688         FLAC__metadata_object_delete(block);
689
690         if(!FLAC__metadata_simple_iterator_next(iterator))
691                 return die_("forward iterator ended early");
692         our_current_position++;
693
694         if(!FLAC__metadata_simple_iterator_next(iterator))
695                 return die_("forward iterator ended early");
696         our_current_position++;
697
698         if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING)
699                 return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
700         if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
701                 return die_("getting block 2");
702         if(block->type != FLAC__METADATA_TYPE_PADDING)
703                 return die_("expected PADDING type");
704         if(!block->is_last)
705                 return die_("expected is_last to be true");
706         /* check to see if some basic data matches (c.f. generate_file_()) */
707         if(block->length != 1234)
708                 return die_("bad PADDING length");
709         FLAC__metadata_object_delete(block);
710
711         if(FLAC__metadata_simple_iterator_next(iterator))
712                 return die_("forward iterator returned true but should have returned false");
713
714         printf("iterate backwards\n");
715         if(!FLAC__metadata_simple_iterator_prev(iterator))
716                 return die_("reverse iterator ended early");
717         if(!FLAC__metadata_simple_iterator_prev(iterator))
718                 return die_("reverse iterator ended early");
719         if(FLAC__metadata_simple_iterator_prev(iterator))
720                 return die_("reverse iterator returned true but should have returned false");
721
722         printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
723
724         if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false))
725                 printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
726         else
727                 return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
728
729         FLAC__metadata_simple_iterator_delete(iterator);
730
731         /************************************************************/
732
733         printf("simple iterator on writable file\n");
734
735         if(!change_stats_(flacfile_, /*read-only=*/false))
736                 return false;
737
738         printf("creating APPLICATION block\n");
739
740         if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
741                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
742         memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
743
744         printf("creating PADDING block\n");
745
746         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
747                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
748         padding->length = 20;
749
750         if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
751                 return die_("FLAC__metadata_simple_iterator_new()");
752
753         if(!FLAC__metadata_simple_iterator_init(iterator, flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
754                 return die_("FLAC__metadata_simple_iterator_init() returned false");
755         our_current_position = 0;
756
757         printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
758
759         printf("[S]VP\ttry to write over STREAMINFO block...\n");
760         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
761                 printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
762         else
763                 return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
764
765         printf("[S]VP\tnext\n");
766         if(!FLAC__metadata_simple_iterator_next(iterator))
767                 return die_("iterator ended early\n");
768         our_current_position++;
769
770         printf("S[V]P\tnext\n");
771         if(!FLAC__metadata_simple_iterator_next(iterator))
772                 return die_("iterator ended early\n");
773         our_current_position++;
774
775         printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
776         padding->length = 25;
777         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
778                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
779         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
780                 return false;
781
782         printf("SVP[P]\tprev\n");
783         if(!FLAC__metadata_simple_iterator_prev(iterator))
784                 return die_("iterator ended early\n");
785         our_current_position--;
786
787         printf("SV[P]P\tprev\n");
788         if(!FLAC__metadata_simple_iterator_prev(iterator))
789                 return die_("iterator ended early\n");
790         our_current_position--;
791
792         printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
793         padding->length = 30;
794         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
795                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
796         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
797                 return false;
798
799         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
800                 return false;
801
802         printf("SV[P]PP\tprev\n");
803         if(!FLAC__metadata_simple_iterator_prev(iterator))
804                 return die_("iterator ended early\n");
805         our_current_position--;
806
807         printf("S[V]PPP\tprev\n");
808         if(!FLAC__metadata_simple_iterator_prev(iterator))
809                 return die_("iterator ended early\n");
810         our_current_position--;
811
812         printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
813         if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
814                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
815
816         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
817                 return false;
818
819         printf("[S]VPPP\tnext\n");
820         if(!FLAC__metadata_simple_iterator_next(iterator))
821                 return die_("iterator ended early\n");
822         our_current_position++;
823
824         printf("S[V]PPP\tnext\n");
825         if(!FLAC__metadata_simple_iterator_next(iterator))
826                 return die_("iterator ended early\n");
827         our_current_position++;
828
829         printf("SV[P]PP\tdelete (middle block), replace with padding\n");
830         if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
831                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
832         our_current_position--;
833
834         printf("S[V]PPP\tnext\n");
835         if(!FLAC__metadata_simple_iterator_next(iterator))
836                 return die_("iterator ended early\n");
837         our_current_position++;
838
839         printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
840         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
841                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
842         delete_from_our_metadata_(our_current_position--);
843
844         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
845                 return false;
846
847         printf("S[V]PP\tnext\n");
848         if(!FLAC__metadata_simple_iterator_next(iterator))
849                 return die_("iterator ended early\n");
850         our_current_position++;
851
852         printf("SV[P]P\tnext\n");
853         if(!FLAC__metadata_simple_iterator_next(iterator))
854                 return die_("iterator ended early\n");
855         our_current_position++;
856
857         printf("SVP[P]\tdelete (last block), replace with padding\n");
858         if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
859                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
860         our_current_position--;
861
862         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
863                 return false;
864
865         printf("SV[P]P\tnext\n");
866         if(!FLAC__metadata_simple_iterator_next(iterator))
867                 return die_("iterator ended early\n");
868         our_current_position++;
869
870         printf("SVP[P]\tdelete (last block), don't replace with padding\n");
871         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
872                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
873         delete_from_our_metadata_(our_current_position--);
874
875         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
876                 return false;
877
878         printf("SV[P]\tprev\n");
879         if(!FLAC__metadata_simple_iterator_prev(iterator))
880                 return die_("iterator ended early\n");
881         our_current_position--;
882
883         printf("S[V]P\tprev\n");
884         if(!FLAC__metadata_simple_iterator_prev(iterator))
885                 return die_("iterator ended early\n");
886         our_current_position--;
887
888         printf("[S]VP\tset STREAMINFO (change sample rate)\n");
889         FLAC__ASSERT(our_current_position == 0);
890         block = FLAC__metadata_simple_iterator_get_block(iterator);
891         block->data.stream_info.sample_rate = 32000;
892         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
893                 return die_("copying object");
894         if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
895                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
896         FLAC__metadata_object_delete(block);
897
898         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
899                 return false;
900
901         printf("[S]VP\tnext\n");
902         if(!FLAC__metadata_simple_iterator_next(iterator))
903                 return die_("iterator ended early\n");
904         our_current_position++;
905
906         printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
907         app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
908         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
909                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
910         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
911                 return false;
912         our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
913
914         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
915                 return false;
916
917         printf("SV[A]P\tnext\n");
918         if(!FLAC__metadata_simple_iterator_next(iterator))
919                 return die_("iterator ended early\n");
920         our_current_position++;
921
922         printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
923         app->data.application.id[0] = 'f'; /* twiddle the id */
924         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
925                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
926         if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
927                 return false;
928         our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
929
930         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
931                 return false;
932
933         printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
934         app->data.application.id[0] = 'g'; /* twiddle the id */
935         if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
936                 return die_("setting APPLICATION data");
937         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
938                 return die_("copying object");
939         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
940                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
941
942         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
943                 return false;
944
945         printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
946         app->data.application.id[0] = 'h'; /* twiddle the id */
947         if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
948                 return die_("setting APPLICATION data");
949         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
950                 return die_("copying object");
951         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
952                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
953
954         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
955                 return false;
956
957         printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
958         app->data.application.id[0] = 'i'; /* twiddle the id */
959         if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
960                 return die_("setting APPLICATION data");
961         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
962                 return die_("copying object");
963         our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
964         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
965                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
966
967         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
968                 return false;
969
970         printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
971         app->data.application.id[0] = 'j'; /* twiddle the id */
972         if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
973                 return die_("setting APPLICATION data");
974         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
975                 return die_("copying object");
976         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
977                 return die_("copying object");
978         our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
979         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
980                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
981
982         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
983                 return false;
984
985         printf("SVA[A]PP\tnext\n");
986         if(!FLAC__metadata_simple_iterator_next(iterator))
987                 return die_("iterator ended early\n");
988         our_current_position++;
989
990         printf("SVAA[P]P\tnext\n");
991         if(!FLAC__metadata_simple_iterator_next(iterator))
992                 return die_("iterator ended early\n");
993         our_current_position++;
994
995         printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
996         padding->length = 5;
997         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
998                 return die_("copying object");
999         if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1000                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1001
1002         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1003                 return false;
1004
1005         printf("SVAAP[P]\tset APPLICATION (grow)\n");
1006         app->data.application.id[0] = 'k'; /* twiddle the id */
1007         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1008                 return die_("copying object");
1009         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1010                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1011
1012         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1013                 return false;
1014
1015         printf("SVAAP[A]\tset PADDING (equal)\n");
1016         padding->length = 27;
1017         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1018                 return die_("copying object");
1019         if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1020                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1021
1022         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1023                 return false;
1024
1025         printf("SVAAP[P]\tprev\n");
1026         if(!FLAC__metadata_simple_iterator_prev(iterator))
1027                 return die_("iterator ended early\n");
1028         our_current_position--;
1029
1030         printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1031         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1032                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1033         delete_from_our_metadata_(our_current_position--);
1034
1035         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1036                 return false;
1037
1038         printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1039         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1040                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1041         delete_from_our_metadata_(our_current_position--);
1042
1043         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1044                 return false;
1045
1046         printf("SV[A]P\tnext\n");
1047         if(!FLAC__metadata_simple_iterator_next(iterator))
1048                 return die_("iterator ended early\n");
1049         our_current_position++;
1050
1051         printf("SVA[P]\tinsert PADDING after\n");
1052         padding->length = 5;
1053         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1054                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1055         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1056                 return false;
1057
1058         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1059                 return false;
1060
1061         printf("SVAP[P]\tprev\n");
1062         if(!FLAC__metadata_simple_iterator_prev(iterator))
1063                 return die_("iterator ended early\n");
1064         our_current_position--;
1065
1066         printf("SVA[P]P\tprev\n");
1067         if(!FLAC__metadata_simple_iterator_prev(iterator))
1068                 return die_("iterator ended early\n");
1069         our_current_position--;
1070
1071         printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1072         if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
1073                 return die_("setting APPLICATION data");
1074         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1075                 return die_("copying object");
1076         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1077                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1078
1079         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1080                 return false;
1081
1082         printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1083         if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
1084                 return die_("setting APPLICATION data");
1085         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1086                 return die_("copying object");
1087         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1088                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1089
1090         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1091                 return false;
1092
1093         printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1094         if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
1095                 return die_("setting APPLICATION data");
1096         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1097                 return die_("copying object");
1098         our_metadata_.blocks[our_current_position+1]->length = 0;
1099         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1100                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1101
1102         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1103                 return false;
1104
1105         printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1106         if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
1107                 return die_("setting APPLICATION data");
1108         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1109                 return die_("copying object");
1110         delete_from_our_metadata_(our_current_position+1);
1111         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1112                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1113
1114         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1115                 return false;
1116
1117         printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1118         if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1119                 return die_("setting APPLICATION data");
1120         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1121                 return die_("copying object");
1122         delete_from_our_metadata_(our_current_position+1);
1123         our_metadata_.blocks[our_current_position]->is_last = true;
1124         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1125                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1126
1127         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1128                 return false;
1129
1130         printf("SV[A]\tset PADDING (equal size)\n");
1131         padding->length = app->length;
1132         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1133                 return die_("copying object");
1134         if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
1135                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
1136
1137         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1138                 return false;
1139
1140         printf("SV[P]\tinsert PADDING after\n");
1141         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1142                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1143         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1144                 return false;
1145
1146         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1147                 return false;
1148
1149         printf("SVP[P]\tinsert PADDING after\n");
1150         padding->length = 5;
1151         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1152                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1153         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1154                 return false;
1155
1156         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1157                 return false;
1158
1159         printf("SVPP[P]\tprev\n");
1160         if(!FLAC__metadata_simple_iterator_prev(iterator))
1161                 return die_("iterator ended early\n");
1162         our_current_position--;
1163
1164         printf("SVP[P]P\tprev\n");
1165         if(!FLAC__metadata_simple_iterator_prev(iterator))
1166                 return die_("iterator ended early\n");
1167         our_current_position--;
1168
1169         printf("SV[P]PP\tprev\n");
1170         if(!FLAC__metadata_simple_iterator_prev(iterator))
1171                 return die_("iterator ended early\n");
1172         our_current_position--;
1173
1174         printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1175         if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1176                 return die_("setting APPLICATION data");
1177         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1178                 return die_("copying object");
1179         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1180                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1181
1182         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1183                 return false;
1184
1185         printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1186         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1187                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1188         delete_from_our_metadata_(our_current_position--);
1189
1190         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1191                 return false;
1192
1193         printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1194         if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1195                 return die_("setting APPLICATION data");
1196         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1197                 return die_("copying object");
1198         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1199                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1200
1201         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1202                 return false;
1203
1204         printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1205         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1206                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1207         delete_from_our_metadata_(our_current_position--);
1208
1209         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1210                 return false;
1211
1212         printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1213         if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1214                 return die_("setting APPLICATION data");
1215         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1216                 return die_("copying object");
1217         delete_from_our_metadata_(our_current_position+1);
1218         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1219                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1220
1221         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1222                 return false;
1223
1224         printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1225         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1226                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1227         delete_from_our_metadata_(our_current_position--);
1228
1229         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1230                 return false;
1231
1232         printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1233         if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1234                 return die_("setting APPLICATION data");
1235         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1236                 return die_("copying object");
1237         our_metadata_.blocks[our_current_position+1]->length = 0;
1238         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1239                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1240
1241         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1242                 return false;
1243
1244         printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1245         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1246                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1247         delete_from_our_metadata_(our_current_position--);
1248
1249         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1250                 return false;
1251
1252         printf("S[V]PP\tnext\n");
1253         if(!FLAC__metadata_simple_iterator_next(iterator))
1254                 return die_("iterator ended early\n");
1255         our_current_position++;
1256
1257         printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1258         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1259                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1260         delete_from_our_metadata_(our_current_position--);
1261
1262         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1263                 return false;
1264
1265         printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1266         if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1267                 return die_("setting APPLICATION data");
1268         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1269                 return die_("copying object");
1270         delete_from_our_metadata_(our_current_position+1);
1271         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1272                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1273
1274         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1275                 return false;
1276
1277         printf("delete simple iterator\n");
1278
1279         FLAC__metadata_simple_iterator_delete(iterator);
1280
1281         FLAC__metadata_object_delete(app);
1282         FLAC__metadata_object_delete(padding);
1283
1284         if(!remove_file_(flacfile_))
1285                 return false;
1286
1287         return true;
1288 }
1289
1290 static FLAC__bool test_level_2_(FLAC__bool filename_based)
1291 {
1292         FLAC__Metadata_Iterator *iterator;
1293         FLAC__Metadata_Chain *chain;
1294         FLAC__StreamMetadata *block, *app, *padding;
1295         FLAC__byte data[2000];
1296         unsigned our_current_position;
1297
1298         /* initialize 'data' to avoid Valgrind errors */
1299         memset(data, 0, sizeof(data));
1300
1301         printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1302
1303         printf("generate read-only file\n");
1304
1305         if(!generate_file_())
1306                 return false;
1307
1308         if(!change_stats_(flacfile_, /*read_only=*/true))
1309                 return false;
1310
1311         printf("create chain\n");
1312
1313         if(0 == (chain = FLAC__metadata_chain_new()))
1314                 return die_("allocating chain");
1315
1316         printf("read chain\n");
1317
1318         if(!chain_read_(chain, flacfile_, filename_based))
1319                 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1320
1321         printf("[S]VP\ttest initial metadata\n");
1322
1323         if(!compare_chain_(chain, 0, 0))
1324                 return false;
1325         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1326                 return false;
1327
1328         printf("switch file to read-write\n");
1329
1330         if(!change_stats_(flacfile_, /*read-only=*/false))
1331                 return false;
1332
1333         printf("create iterator\n");
1334         if(0 == (iterator = FLAC__metadata_iterator_new()))
1335                 return die_("allocating memory for iterator");
1336
1337         our_current_position = 0;
1338
1339         FLAC__metadata_iterator_init(iterator, chain);
1340
1341         if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1342                 return die_("getting block from iterator");
1343
1344         FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1345
1346         printf("[S]VP\tmodify STREAMINFO, write\n");
1347
1348         block->data.stream_info.sample_rate = 32000;
1349         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1350                 return die_("copying object");
1351
1352         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1353                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1354         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1355                 return false;
1356         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1357                 return false;
1358
1359         printf("[S]VP\tnext\n");
1360         if(!FLAC__metadata_iterator_next(iterator))
1361                 return die_("iterator ended early\n");
1362         our_current_position++;
1363
1364         printf("S[V]P\tnext\n");
1365         if(!FLAC__metadata_iterator_next(iterator))
1366                 return die_("iterator ended early\n");
1367         our_current_position++;
1368
1369         printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1370         if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1371                 return die_("getting block from iterator");
1372         if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1373                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1374         memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1375         if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1376                 return die_("setting APPLICATION data");
1377         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1378                 return die_("copying object");
1379         if(!FLAC__metadata_iterator_set_block(iterator, app))
1380                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1381
1382         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1383                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1384         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1385                 return false;
1386         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1387                 return false;
1388
1389         printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1390         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1391                 return die_("copying object");
1392         if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1393                 return die_("setting APPLICATION data");
1394         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1395                 return die_("copying object");
1396         if(!FLAC__metadata_iterator_set_block(iterator, app))
1397                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1398
1399         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1400                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1401         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1402                 return false;
1403         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1404                 return false;
1405
1406         printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1407         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1408                 return die_("copying object");
1409         if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1410                 return die_("setting APPLICATION data");
1411         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1412                 return die_("copying object");
1413         if(!FLAC__metadata_iterator_set_block(iterator, app))
1414                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1415
1416         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1417                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1418         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1419                 return false;
1420         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1421                 return false;
1422
1423         printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1424         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1425                 return die_("copying object");
1426         if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1427                 return die_("setting APPLICATION data");
1428         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1429                 return die_("copying object");
1430         if(!FLAC__metadata_iterator_set_block(iterator, app))
1431                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1432
1433         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1434                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1435         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1436                 return false;
1437         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1438                 return false;
1439
1440         printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1441         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1442                 return die_("copying object");
1443         if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1444                 return die_("setting APPLICATION data");
1445         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1446                 return die_("copying object");
1447         if(!FLAC__metadata_iterator_set_block(iterator, app))
1448                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1449
1450         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1451                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1452         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1453                 return false;
1454         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1455                 return false;
1456
1457         printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1458         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1459                 return die_("creating PADDING block");
1460         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1461                 return die_("copying object");
1462         if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1463                 return die_("setting APPLICATION data");
1464         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1465                 return die_("copying object");
1466         padding->length = 0;
1467         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1468                 return die_("internal error");
1469         if(!FLAC__metadata_iterator_set_block(iterator, app))
1470                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1471
1472         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1473                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1474         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1475                 return false;
1476         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1477                 return false;
1478
1479         printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1480         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1481                 return die_("copying object");
1482         if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1483                 return die_("setting APPLICATION data");
1484         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1485                 return die_("copying object");
1486         our_metadata_.blocks[our_current_position+1]->length = 13;
1487         if(!FLAC__metadata_iterator_set_block(iterator, app))
1488                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1489
1490         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1491                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1492         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1493                 return false;
1494         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1495                 return false;
1496
1497         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1498         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1499                 return die_("copying object");
1500         if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1501                 return die_("setting APPLICATION data");
1502         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1503                 return die_("copying object");
1504         if(!FLAC__metadata_iterator_set_block(iterator, app))
1505                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1506
1507         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1508                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1509         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1510                 return false;
1511         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1512                 return false;
1513
1514         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1515         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1516                 return die_("copying object");
1517         if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1518                 return die_("setting APPLICATION data");
1519         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1520                 return die_("copying object");
1521         our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1522         if(!FLAC__metadata_iterator_set_block(iterator, app))
1523                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1524
1525         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1526                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1527         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1528                 return false;
1529         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1530                 return false;
1531
1532         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1533         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1534                 return die_("copying object");
1535         if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1536                 return die_("setting APPLICATION data");
1537         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1538                 return die_("copying object");
1539         delete_from_our_metadata_(our_current_position+1);
1540         if(!FLAC__metadata_iterator_set_block(iterator, app))
1541                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1542
1543         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1544                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1545         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1546                 return false;
1547         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1548                 return false;
1549
1550         printf("SV[A]\tprev\n");
1551         if(!FLAC__metadata_iterator_prev(iterator))
1552                 return die_("iterator ended early\n");
1553         our_current_position--;
1554
1555         printf("S[V]A\tprev\n");
1556         if(!FLAC__metadata_iterator_prev(iterator))
1557                 return die_("iterator ended early\n");
1558         our_current_position--;
1559
1560         printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1561         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1562                 return die_("creating PADDING block");
1563         padding->length = 30;
1564         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1565                 printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1566         else
1567                 return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1568
1569         printf("[S]VP\tnext\n");
1570         if(!FLAC__metadata_iterator_next(iterator))
1571                 return die_("iterator ended early\n");
1572         our_current_position++;
1573
1574         printf("S[V]A\tinsert PADDING after\n");
1575         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1576                 return die_("copying metadata");
1577         if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1578                 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1579
1580         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1581                 return false;
1582
1583         printf("SV[P]A\tinsert PADDING before\n");
1584         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1585                 return die_("creating PADDING block");
1586         padding->length = 17;
1587         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1588                 return die_("copying metadata");
1589         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1590                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1591
1592         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1593                 return false;
1594
1595         printf("SV[P]PA\tinsert PADDING before\n");
1596         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1597                 return die_("creating PADDING block");
1598         padding->length = 0;
1599         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1600                 return die_("copying metadata");
1601         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1602                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1603
1604         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1605                 return false;
1606
1607         printf("SV[P]PPA\tnext\n");
1608         if(!FLAC__metadata_iterator_next(iterator))
1609                 return die_("iterator ended early\n");
1610         our_current_position++;
1611
1612         printf("SVP[P]PA\tnext\n");
1613         if(!FLAC__metadata_iterator_next(iterator))
1614                 return die_("iterator ended early\n");
1615         our_current_position++;
1616
1617         printf("SVPP[P]A\tnext\n");
1618         if(!FLAC__metadata_iterator_next(iterator))
1619                 return die_("iterator ended early\n");
1620         our_current_position++;
1621
1622         printf("SVPPP[A]\tinsert PADDING after\n");
1623         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1624                 return die_("creating PADDING block");
1625         padding->length = 57;
1626         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1627                 return die_("copying metadata");
1628         if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1629                 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1630
1631         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1632                 return false;
1633
1634         printf("SVPPPA[P]\tinsert PADDING before\n");
1635         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1636                 return die_("creating PADDING block");
1637         padding->length = 99;
1638         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1639                 return die_("copying metadata");
1640         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1641                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1642
1643         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1644                 return false;
1645
1646         printf("delete iterator\n");
1647         FLAC__metadata_iterator_delete(iterator);
1648         our_current_position = 0;
1649
1650         printf("SVPPPAPP\tmerge padding\n");
1651         FLAC__metadata_chain_merge_padding(chain);
1652         our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1653         our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
1654         our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
1655         delete_from_our_metadata_(7);
1656         delete_from_our_metadata_(4);
1657         delete_from_our_metadata_(3);
1658
1659         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1660                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1661         if(!compare_chain_(chain, 0, 0))
1662                 return false;
1663         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1664                 return false;
1665
1666         printf("SVPAP\tsort padding\n");
1667         FLAC__metadata_chain_sort_padding(chain);
1668         our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1669         delete_from_our_metadata_(2);
1670
1671         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1672                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1673         if(!compare_chain_(chain, 0, 0))
1674                 return false;
1675         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1676                 return false;
1677
1678         printf("create iterator\n");
1679         if(0 == (iterator = FLAC__metadata_iterator_new()))
1680                 return die_("allocating memory for iterator");
1681
1682         our_current_position = 0;
1683
1684         FLAC__metadata_iterator_init(iterator, chain);
1685
1686         printf("[S]VAP\tnext\n");
1687         if(!FLAC__metadata_iterator_next(iterator))
1688                 return die_("iterator ended early\n");
1689         our_current_position++;
1690
1691         printf("S[V]AP\tnext\n");
1692         if(!FLAC__metadata_iterator_next(iterator))
1693                 return die_("iterator ended early\n");
1694         our_current_position++;
1695
1696         printf("SV[A]P\tdelete middle block, replace with padding\n");
1697         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1698                 return die_("creating PADDING block");
1699         padding->length = 71;
1700         if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1701                 return die_("copying object");
1702         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1703                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1704
1705         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1706                 return false;
1707
1708         printf("S[V]PP\tnext\n");
1709         if(!FLAC__metadata_iterator_next(iterator))
1710                 return die_("iterator ended early\n");
1711         our_current_position++;
1712
1713         printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1714         delete_from_our_metadata_(our_current_position--);
1715         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1716                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1717
1718         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1719                 return false;
1720
1721         printf("S[V]P\tnext\n");
1722         if(!FLAC__metadata_iterator_next(iterator))
1723                 return die_("iterator ended early\n");
1724         our_current_position++;
1725
1726         printf("SV[P]\tdelete last block, replace with padding\n");
1727         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1728                 return die_("creating PADDING block");
1729         padding->length = 219;
1730         if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1731                 return die_("copying object");
1732         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1733                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1734
1735         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1736                 return false;
1737
1738         printf("S[V]P\tnext\n");
1739         if(!FLAC__metadata_iterator_next(iterator))
1740                 return die_("iterator ended early\n");
1741         our_current_position++;
1742
1743         printf("SV[P]\tdelete last block, don't replace with padding\n");
1744         delete_from_our_metadata_(our_current_position--);
1745         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1746                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1747
1748         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1749                 return false;
1750
1751         printf("S[V]\tprev\n");
1752         if(!FLAC__metadata_iterator_prev(iterator))
1753                 return die_("iterator ended early\n");
1754         our_current_position--;
1755
1756         printf("[S]V\tdelete STREAMINFO block, should fail\n");
1757         if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1758                 return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
1759
1760         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1761                 return false;
1762
1763         printf("delete iterator\n");
1764         FLAC__metadata_iterator_delete(iterator);
1765         our_current_position = 0;
1766
1767         printf("SV\tmerge padding\n");
1768         FLAC__metadata_chain_merge_padding(chain);
1769
1770         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1771                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1772         if(!compare_chain_(chain, 0, 0))
1773                 return false;
1774         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1775                 return false;
1776
1777         printf("SV\tsort padding\n");
1778         FLAC__metadata_chain_sort_padding(chain);
1779
1780         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1781                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1782         if(!compare_chain_(chain, 0, 0))
1783                 return false;
1784         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1785                 return false;
1786
1787         printf("delete chain\n");
1788
1789         FLAC__metadata_chain_delete(chain);
1790
1791         if(!remove_file_(flacfile_))
1792                 return false;
1793
1794         return true;
1795 }
1796
1797 FLAC__bool test_metadata_file_manipulation()
1798 {
1799         printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
1800
1801         our_metadata_.num_blocks = 0;
1802
1803         if(!test_level_0_())
1804                 return false;
1805
1806         if(!test_level_1_())
1807                 return false;
1808
1809         if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
1810                 return false;
1811         if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
1812                 return false;
1813
1814         return true;
1815 }