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