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