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