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