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