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