change default padding to 8K, or 64K if input audio stream is >= 20 minutes long
[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_COLORS_LEN +
560                                 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
561                         ) / 8
562                 ;
563                 picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
564                 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
565                 picture.length += strlen(picture.data.picture.mime_type);
566                 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
567                 picture.length += strlen((const char *)picture.data.picture.description);
568                 picture.data.picture.width = 300;
569                 picture.data.picture.height = 300;
570                 picture.data.picture.depth = 24;
571                 picture.data.picture.colors = 0;
572                 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
573                 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
574                 picture.length += picture.data.picture.data_length;
575         }
576
577         padding.is_last = true;
578         padding.type = FLAC__METADATA_TYPE_PADDING;
579         padding.length = 1234;
580
581         metadata[n++] = &vorbiscomment;
582         if(include_extras) {
583                 metadata[n++] = cuesheet;
584                 metadata[n++] = &picture;
585         }
586         metadata[n++] = &padding;
587
588         if(
589                 !insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
590                 !insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
591                 (include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
592                 (include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
593                 !insert_to_our_metadata_(&padding, i++, /*copy=*/true)
594         )
595                 return die_("priming our metadata");
596
597         if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
598                 return die_("creating the encoded file");
599
600         free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
601
602         return true;
603 }
604
605 static FLAC__bool test_file_(const char *filename, FLAC__StreamDecoderMetadataCallback metadata_callback)
606 {
607         FLAC__StreamDecoder *decoder;
608         decoder_client_struct decoder_client_data;
609
610         FLAC__ASSERT(0 != filename);
611         FLAC__ASSERT(0 != metadata_callback);
612
613         mc_our_block_number_ = 0;
614         decoder_client_data.error_occurred = false;
615
616         printf("\ttesting '%s'... ", filename);
617         fflush(stdout);
618
619         if(0 == (decoder = FLAC__stream_decoder_new()))
620                 return die_("couldn't allocate decoder instance");
621
622         FLAC__stream_decoder_set_md5_checking(decoder, true);
623         FLAC__stream_decoder_set_metadata_respond_all(decoder);
624         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) {
625                 FLAC__stream_decoder_finish(decoder);
626                 FLAC__stream_decoder_delete(decoder);
627                 return die_("initializing decoder\n");
628         }
629         if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
630                 FLAC__stream_decoder_finish(decoder);
631                 FLAC__stream_decoder_delete(decoder);
632                 return die_("decoding file\n");
633         }
634
635         FLAC__stream_decoder_finish(decoder);
636         FLAC__stream_decoder_delete(decoder);
637
638         if(decoder_client_data.error_occurred)
639                 return false;
640
641         if(mc_our_block_number_ != our_metadata_.num_blocks)
642                 return die_("short metadata block count");
643
644         printf("PASSED\n");
645         return true;
646 }
647
648 static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
649 {
650         if(!grabbag__file_change_stats(filename, read_only))
651                 return die_("during grabbag__file_change_stats()");
652
653         return true;
654 }
655
656 static FLAC__bool remove_file_(const char *filename)
657 {
658         while(our_metadata_.num_blocks > 0)
659                 delete_from_our_metadata_(0);
660
661         if(!grabbag__file_remove_file(filename))
662                 return die_("removing file");
663
664         return true;
665 }
666
667 static FLAC__bool test_level_0_()
668 {
669         FLAC__StreamMetadata streaminfo;
670         FLAC__StreamMetadata *tags = 0;
671         FLAC__StreamMetadata *cuesheet = 0;
672         FLAC__StreamMetadata *picture = 0;
673
674         printf("\n\n++++++ testing level 0 interface\n");
675
676         if(!generate_file_(/*include_extras=*/true))
677                 return false;
678
679         if(!test_file_(flacfile_, decoder_metadata_callback_null_))
680                 return false;
681
682         printf("testing FLAC__metadata_get_streaminfo()... ");
683
684         if(!FLAC__metadata_get_streaminfo(flacfile_, &streaminfo))
685                 return die_("during FLAC__metadata_get_streaminfo()");
686
687         /* check to see if some basic data matches (c.f. generate_file_()) */
688         if(streaminfo.data.stream_info.channels != 1)
689                 return die_("mismatch in streaminfo.data.stream_info.channels");
690         if(streaminfo.data.stream_info.bits_per_sample != 8)
691                 return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
692         if(streaminfo.data.stream_info.sample_rate != 44100)
693                 return die_("mismatch in streaminfo.data.stream_info.sample_rate");
694         if(streaminfo.data.stream_info.min_blocksize != 576)
695                 return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
696         if(streaminfo.data.stream_info.max_blocksize != 576)
697                 return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
698
699         printf("OK\n");
700
701         printf("testing FLAC__metadata_get_tags()... ");
702
703         if(!FLAC__metadata_get_tags(flacfile_, &tags))
704                 return die_("during FLAC__metadata_get_tags()");
705
706         /* check to see if some basic data matches (c.f. generate_file_()) */
707         if(tags->data.vorbis_comment.num_comments != 0)
708                 return die_("mismatch in tags->data.vorbis_comment.num_comments");
709
710         printf("OK\n");
711
712         FLAC__metadata_object_delete(tags);
713
714         printf("testing FLAC__metadata_get_cuesheet()... ");
715
716         if(!FLAC__metadata_get_cuesheet(flacfile_, &cuesheet))
717                 return die_("during FLAC__metadata_get_cuesheet()");
718
719         /* check to see if some basic data matches (c.f. generate_file_()) */
720         if(cuesheet->data.cue_sheet.lead_in != 123)
721                 return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
722
723         printf("OK\n");
724
725         FLAC__metadata_object_delete(cuesheet);
726
727         printf("testing FLAC__metadata_get_picture()... ");
728
729         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), /*max_colors=*/(unsigned)(-1)))
730                 return die_("during FLAC__metadata_get_picture()");
731
732         /* check to see if some basic data matches (c.f. generate_file_()) */
733         if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
734                 return die_("mismatch in picture->data.picture.type");
735
736         printf("OK\n");
737
738         FLAC__metadata_object_delete(picture);
739
740         if(!remove_file_(flacfile_))
741                 return false;
742
743         return true;
744 }
745
746 static FLAC__bool test_level_1_()
747 {
748         FLAC__Metadata_SimpleIterator *iterator;
749         FLAC__StreamMetadata *block, *app, *padding;
750         FLAC__byte data[1000];
751         unsigned our_current_position = 0;
752
753         /* initialize 'data' to avoid Valgrind errors */
754         memset(data, 0, sizeof(data));
755
756         printf("\n\n++++++ testing level 1 interface\n");
757
758         /************************************************************/
759
760         printf("simple iterator on read-only file\n");
761
762         if(!generate_file_(/*include_extras=*/false))
763                 return false;
764
765         if(!change_stats_(flacfile_, /*read_only=*/true))
766                 return false;
767
768         if(!test_file_(flacfile_, decoder_metadata_callback_null_))
769                 return false;
770
771         if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
772                 return die_("FLAC__metadata_simple_iterator_new()");
773
774         if(!FLAC__metadata_simple_iterator_init(iterator, flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
775                 return die_("FLAC__metadata_simple_iterator_init() returned false");
776
777         printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
778         if(FLAC__metadata_simple_iterator_is_writable(iterator))
779                 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
780
781         printf("iterate forwards\n");
782
783         if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO)
784                 return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
785         if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
786                 return die_("getting block 0");
787         if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
788                 return die_("expected STREAMINFO type");
789         if(block->is_last)
790                 return die_("expected is_last to be false");
791         if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
792                 return die_("bad STREAMINFO length");
793         /* check to see if some basic data matches (c.f. generate_file_()) */
794         if(block->data.stream_info.channels != 1)
795                 return die_("mismatch in channels");
796         if(block->data.stream_info.bits_per_sample != 8)
797                 return die_("mismatch in bits_per_sample");
798         if(block->data.stream_info.sample_rate != 44100)
799                 return die_("mismatch in sample_rate");
800         if(block->data.stream_info.min_blocksize != 576)
801                 return die_("mismatch in min_blocksize");
802         if(block->data.stream_info.max_blocksize != 576)
803                 return die_("mismatch in max_blocksize");
804         FLAC__metadata_object_delete(block);
805
806         if(!FLAC__metadata_simple_iterator_next(iterator))
807                 return die_("forward iterator ended early");
808         our_current_position++;
809
810         if(!FLAC__metadata_simple_iterator_next(iterator))
811                 return die_("forward iterator ended early");
812         our_current_position++;
813
814         if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING)
815                 return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
816         if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
817                 return die_("getting block 2");
818         if(block->type != FLAC__METADATA_TYPE_PADDING)
819                 return die_("expected PADDING type");
820         if(!block->is_last)
821                 return die_("expected is_last to be true");
822         /* check to see if some basic data matches (c.f. generate_file_()) */
823         if(block->length != 1234)
824                 return die_("bad PADDING length");
825         FLAC__metadata_object_delete(block);
826
827         if(FLAC__metadata_simple_iterator_next(iterator))
828                 return die_("forward iterator returned true but should have returned false");
829
830         printf("iterate backwards\n");
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 ended early");
835         if(FLAC__metadata_simple_iterator_prev(iterator))
836                 return die_("reverse iterator returned true but should have returned false");
837
838         printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
839
840         if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false))
841                 printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
842         else
843                 return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
844
845         FLAC__metadata_simple_iterator_delete(iterator);
846
847         /************************************************************/
848
849         printf("simple iterator on writable file\n");
850
851         if(!change_stats_(flacfile_, /*read-only=*/false))
852                 return false;
853
854         printf("creating APPLICATION block\n");
855
856         if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
857                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
858         memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
859
860         printf("creating PADDING block\n");
861
862         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
863                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
864         padding->length = 20;
865
866         if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
867                 return die_("FLAC__metadata_simple_iterator_new()");
868
869         if(!FLAC__metadata_simple_iterator_init(iterator, flacfile_, /*read_only=*/false, /*preserve_file_stats=*/false))
870                 return die_("FLAC__metadata_simple_iterator_init() returned false");
871         our_current_position = 0;
872
873         printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
874
875         printf("[S]VP\ttry to write over STREAMINFO block...\n");
876         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
877                 printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
878         else
879                 return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
880
881         printf("[S]VP\tnext\n");
882         if(!FLAC__metadata_simple_iterator_next(iterator))
883                 return die_("iterator ended early\n");
884         our_current_position++;
885
886         printf("S[V]P\tnext\n");
887         if(!FLAC__metadata_simple_iterator_next(iterator))
888                 return die_("iterator ended early\n");
889         our_current_position++;
890
891         printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
892         padding->length = 25;
893         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
894                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
895         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
896                 return false;
897
898         printf("SVP[P]\tprev\n");
899         if(!FLAC__metadata_simple_iterator_prev(iterator))
900                 return die_("iterator ended early\n");
901         our_current_position--;
902
903         printf("SV[P]P\tprev\n");
904         if(!FLAC__metadata_simple_iterator_prev(iterator))
905                 return die_("iterator ended early\n");
906         our_current_position--;
907
908         printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
909         padding->length = 30;
910         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
911                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
912         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
913                 return false;
914
915         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
916                 return false;
917
918         printf("SV[P]PP\tprev\n");
919         if(!FLAC__metadata_simple_iterator_prev(iterator))
920                 return die_("iterator ended early\n");
921         our_current_position--;
922
923         printf("S[V]PPP\tprev\n");
924         if(!FLAC__metadata_simple_iterator_prev(iterator))
925                 return die_("iterator ended early\n");
926         our_current_position--;
927
928         printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
929         if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
930                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
931
932         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
933                 return false;
934
935         printf("[S]VPPP\tnext\n");
936         if(!FLAC__metadata_simple_iterator_next(iterator))
937                 return die_("iterator ended early\n");
938         our_current_position++;
939
940         printf("S[V]PPP\tnext\n");
941         if(!FLAC__metadata_simple_iterator_next(iterator))
942                 return die_("iterator ended early\n");
943         our_current_position++;
944
945         printf("SV[P]PP\tdelete (middle block), replace with padding\n");
946         if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
947                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
948         our_current_position--;
949
950         printf("S[V]PPP\tnext\n");
951         if(!FLAC__metadata_simple_iterator_next(iterator))
952                 return die_("iterator ended early\n");
953         our_current_position++;
954
955         printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
956         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
957                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
958         delete_from_our_metadata_(our_current_position--);
959
960         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
961                 return false;
962
963         printf("S[V]PP\tnext\n");
964         if(!FLAC__metadata_simple_iterator_next(iterator))
965                 return die_("iterator ended early\n");
966         our_current_position++;
967
968         printf("SV[P]P\tnext\n");
969         if(!FLAC__metadata_simple_iterator_next(iterator))
970                 return die_("iterator ended early\n");
971         our_current_position++;
972
973         printf("SVP[P]\tdelete (last block), replace with padding\n");
974         if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
975                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
976         our_current_position--;
977
978         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
979                 return false;
980
981         printf("SV[P]P\tnext\n");
982         if(!FLAC__metadata_simple_iterator_next(iterator))
983                 return die_("iterator ended early\n");
984         our_current_position++;
985
986         printf("SVP[P]\tdelete (last block), don't replace with padding\n");
987         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
988                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
989         delete_from_our_metadata_(our_current_position--);
990
991         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
992                 return false;
993
994         printf("SV[P]\tprev\n");
995         if(!FLAC__metadata_simple_iterator_prev(iterator))
996                 return die_("iterator ended early\n");
997         our_current_position--;
998
999         printf("S[V]P\tprev\n");
1000         if(!FLAC__metadata_simple_iterator_prev(iterator))
1001                 return die_("iterator ended early\n");
1002         our_current_position--;
1003
1004         printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1005         FLAC__ASSERT(our_current_position == 0);
1006         block = FLAC__metadata_simple_iterator_get_block(iterator);
1007         block->data.stream_info.sample_rate = 32000;
1008         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1009                 return die_("copying object");
1010         if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
1011                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
1012         FLAC__metadata_object_delete(block);
1013
1014         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1015                 return false;
1016
1017         printf("[S]VP\tnext\n");
1018         if(!FLAC__metadata_simple_iterator_next(iterator))
1019                 return die_("iterator ended early\n");
1020         our_current_position++;
1021
1022         printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1023         app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
1024         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1025                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1026         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1027                 return false;
1028         our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1029
1030         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1031                 return false;
1032
1033         printf("SV[A]P\tnext\n");
1034         if(!FLAC__metadata_simple_iterator_next(iterator))
1035                 return die_("iterator ended early\n");
1036         our_current_position++;
1037
1038         printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1039         app->data.application.id[0] = 'f'; /* twiddle the id */
1040         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1041                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1042         if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1043                 return false;
1044         our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1045
1046         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1047                 return false;
1048
1049         printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1050         app->data.application.id[0] = 'g'; /* twiddle the id */
1051         if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1052                 return die_("setting APPLICATION data");
1053         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1054                 return die_("copying object");
1055         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1056                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1057
1058         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1059                 return false;
1060
1061         printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1062         app->data.application.id[0] = 'h'; /* twiddle the id */
1063         if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
1064                 return die_("setting APPLICATION data");
1065         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1066                 return die_("copying object");
1067         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1068                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1069
1070         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1071                 return false;
1072
1073         printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1074         app->data.application.id[0] = 'i'; /* twiddle the id */
1075         if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1076                 return die_("setting APPLICATION data");
1077         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1078                 return die_("copying object");
1079         our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
1080         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1081                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1082
1083         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1084                 return false;
1085
1086         printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1087         app->data.application.id[0] = 'j'; /* twiddle the id */
1088         if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
1089                 return die_("setting APPLICATION data");
1090         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1091                 return die_("copying object");
1092         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1093                 return die_("copying object");
1094         our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
1095         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1096                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1097
1098         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1099                 return false;
1100
1101         printf("SVA[A]PP\tnext\n");
1102         if(!FLAC__metadata_simple_iterator_next(iterator))
1103                 return die_("iterator ended early\n");
1104         our_current_position++;
1105
1106         printf("SVAA[P]P\tnext\n");
1107         if(!FLAC__metadata_simple_iterator_next(iterator))
1108                 return die_("iterator ended early\n");
1109         our_current_position++;
1110
1111         printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1112         padding->length = 5;
1113         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1114                 return die_("copying object");
1115         if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1116                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1117
1118         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1119                 return false;
1120
1121         printf("SVAAP[P]\tset APPLICATION (grow)\n");
1122         app->data.application.id[0] = 'k'; /* twiddle the id */
1123         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1124                 return die_("copying object");
1125         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1126                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1127
1128         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1129                 return false;
1130
1131         printf("SVAAP[A]\tset PADDING (equal)\n");
1132         padding->length = 27;
1133         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1134                 return die_("copying object");
1135         if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1136                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1137
1138         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1139                 return false;
1140
1141         printf("SVAAP[P]\tprev\n");
1142         if(!FLAC__metadata_simple_iterator_prev(iterator))
1143                 return die_("iterator ended early\n");
1144         our_current_position--;
1145
1146         printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1147         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1148                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1149         delete_from_our_metadata_(our_current_position--);
1150
1151         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1152                 return false;
1153
1154         printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1155         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1156                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1157         delete_from_our_metadata_(our_current_position--);
1158
1159         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1160                 return false;
1161
1162         printf("SV[A]P\tnext\n");
1163         if(!FLAC__metadata_simple_iterator_next(iterator))
1164                 return die_("iterator ended early\n");
1165         our_current_position++;
1166
1167         printf("SVA[P]\tinsert PADDING after\n");
1168         padding->length = 5;
1169         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1170                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1171         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1172                 return false;
1173
1174         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1175                 return false;
1176
1177         printf("SVAP[P]\tprev\n");
1178         if(!FLAC__metadata_simple_iterator_prev(iterator))
1179                 return die_("iterator ended early\n");
1180         our_current_position--;
1181
1182         printf("SVA[P]P\tprev\n");
1183         if(!FLAC__metadata_simple_iterator_prev(iterator))
1184                 return die_("iterator ended early\n");
1185         our_current_position--;
1186
1187         printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1188         if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
1189                 return die_("setting APPLICATION data");
1190         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1191                 return die_("copying object");
1192         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1193                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1194
1195         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1196                 return false;
1197
1198         printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1199         if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
1200                 return die_("setting APPLICATION data");
1201         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1202                 return die_("copying object");
1203         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1204                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1205
1206         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1207                 return false;
1208
1209         printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1210         if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
1211                 return die_("setting APPLICATION data");
1212         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1213                 return die_("copying object");
1214         our_metadata_.blocks[our_current_position+1]->length = 0;
1215         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1216                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1217
1218         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1219                 return false;
1220
1221         printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1222         if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
1223                 return die_("setting APPLICATION data");
1224         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1225                 return die_("copying object");
1226         delete_from_our_metadata_(our_current_position+1);
1227         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1228                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1229
1230         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1231                 return false;
1232
1233         printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1234         if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1235                 return die_("setting APPLICATION data");
1236         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1237                 return die_("copying object");
1238         delete_from_our_metadata_(our_current_position+1);
1239         our_metadata_.blocks[our_current_position]->is_last = true;
1240         if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1241                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1242
1243         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1244                 return false;
1245
1246         printf("SV[A]\tset PADDING (equal size)\n");
1247         padding->length = app->length;
1248         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1249                 return die_("copying object");
1250         if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
1251                 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
1252
1253         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1254                 return false;
1255
1256         printf("SV[P]\tinsert PADDING after\n");
1257         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1258                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1259         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1260                 return false;
1261
1262         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1263                 return false;
1264
1265         printf("SVP[P]\tinsert PADDING after\n");
1266         padding->length = 5;
1267         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1268                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1269         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1270                 return false;
1271
1272         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1273                 return false;
1274
1275         printf("SVPP[P]\tprev\n");
1276         if(!FLAC__metadata_simple_iterator_prev(iterator))
1277                 return die_("iterator ended early\n");
1278         our_current_position--;
1279
1280         printf("SVP[P]P\tprev\n");
1281         if(!FLAC__metadata_simple_iterator_prev(iterator))
1282                 return die_("iterator ended early\n");
1283         our_current_position--;
1284
1285         printf("SV[P]PP\tprev\n");
1286         if(!FLAC__metadata_simple_iterator_prev(iterator))
1287                 return die_("iterator ended early\n");
1288         our_current_position--;
1289
1290         printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1291         if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1292                 return die_("setting APPLICATION data");
1293         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1294                 return die_("copying object");
1295         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1296                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1297
1298         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1299                 return false;
1300
1301         printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1302         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1303                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1304         delete_from_our_metadata_(our_current_position--);
1305
1306         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1307                 return false;
1308
1309         printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1310         if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1311                 return die_("setting APPLICATION data");
1312         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1313                 return die_("copying object");
1314         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1315                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1316
1317         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1318                 return false;
1319
1320         printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1321         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1322                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1323         delete_from_our_metadata_(our_current_position--);
1324
1325         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1326                 return false;
1327
1328         printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1329         if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1330                 return die_("setting APPLICATION data");
1331         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1332                 return die_("copying object");
1333         delete_from_our_metadata_(our_current_position+1);
1334         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1335                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1336
1337         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1338                 return false;
1339
1340         printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1341         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1342                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1343         delete_from_our_metadata_(our_current_position--);
1344
1345         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1346                 return false;
1347
1348         printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1349         if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1350                 return die_("setting APPLICATION data");
1351         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1352                 return die_("copying object");
1353         our_metadata_.blocks[our_current_position+1]->length = 0;
1354         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1355                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1356
1357         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1358                 return false;
1359
1360         printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1361         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1362                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1363         delete_from_our_metadata_(our_current_position--);
1364
1365         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1366                 return false;
1367
1368         printf("S[V]PP\tnext\n");
1369         if(!FLAC__metadata_simple_iterator_next(iterator))
1370                 return die_("iterator ended early\n");
1371         our_current_position++;
1372
1373         printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1374         if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1375                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1376         delete_from_our_metadata_(our_current_position--);
1377
1378         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1379                 return false;
1380
1381         printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1382         if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1383                 return die_("setting APPLICATION data");
1384         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1385                 return die_("copying object");
1386         delete_from_our_metadata_(our_current_position+1);
1387         if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1388                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1389
1390         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1391                 return false;
1392
1393         printf("delete simple iterator\n");
1394
1395         FLAC__metadata_simple_iterator_delete(iterator);
1396
1397         FLAC__metadata_object_delete(app);
1398         FLAC__metadata_object_delete(padding);
1399
1400         if(!remove_file_(flacfile_))
1401                 return false;
1402
1403         return true;
1404 }
1405
1406 static FLAC__bool test_level_2_(FLAC__bool filename_based)
1407 {
1408         FLAC__Metadata_Iterator *iterator;
1409         FLAC__Metadata_Chain *chain;
1410         FLAC__StreamMetadata *block, *app, *padding;
1411         FLAC__byte data[2000];
1412         unsigned our_current_position;
1413
1414         /* initialize 'data' to avoid Valgrind errors */
1415         memset(data, 0, sizeof(data));
1416
1417         printf("\n\n++++++ testing level 2 interface (%s-based)\n", filename_based? "filename":"callback");
1418
1419         printf("generate read-only file\n");
1420
1421         if(!generate_file_(/*include_extras=*/false))
1422                 return false;
1423
1424         if(!change_stats_(flacfile_, /*read_only=*/true))
1425                 return false;
1426
1427         printf("create chain\n");
1428
1429         if(0 == (chain = FLAC__metadata_chain_new()))
1430                 return die_("allocating chain");
1431
1432         printf("read chain\n");
1433
1434         if(!read_chain_(chain, flacfile_, filename_based))
1435                 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1436
1437         printf("[S]VP\ttest initial metadata\n");
1438
1439         if(!compare_chain_(chain, 0, 0))
1440                 return false;
1441         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1442                 return false;
1443
1444         printf("switch file to read-write\n");
1445
1446         if(!change_stats_(flacfile_, /*read-only=*/false))
1447                 return false;
1448
1449         printf("create iterator\n");
1450         if(0 == (iterator = FLAC__metadata_iterator_new()))
1451                 return die_("allocating memory for iterator");
1452
1453         our_current_position = 0;
1454
1455         FLAC__metadata_iterator_init(iterator, chain);
1456
1457         if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1458                 return die_("getting block from iterator");
1459
1460         FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1461
1462         printf("[S]VP\tmodify STREAMINFO, write\n");
1463
1464         block->data.stream_info.sample_rate = 32000;
1465         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1466                 return die_("copying object");
1467
1468         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfile_))
1469                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1470         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1471                 return false;
1472         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1473                 return false;
1474
1475         printf("[S]VP\tnext\n");
1476         if(!FLAC__metadata_iterator_next(iterator))
1477                 return die_("iterator ended early\n");
1478         our_current_position++;
1479
1480         printf("S[V]P\tnext\n");
1481         if(!FLAC__metadata_iterator_next(iterator))
1482                 return die_("iterator ended early\n");
1483         our_current_position++;
1484
1485         printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1486         if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1487                 return die_("getting block from iterator");
1488         if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1489                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1490         memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1491         if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1492                 return die_("setting APPLICATION data");
1493         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1494                 return die_("copying object");
1495         if(!FLAC__metadata_iterator_set_block(iterator, app))
1496                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1497
1498         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1499                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1500         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1501                 return false;
1502         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1503                 return false;
1504
1505         printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1506         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1507                 return die_("copying object");
1508         if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1509                 return die_("setting APPLICATION data");
1510         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1511                 return die_("copying object");
1512         if(!FLAC__metadata_iterator_set_block(iterator, app))
1513                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1514
1515         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1516                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1517         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1518                 return false;
1519         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1520                 return false;
1521
1522         printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1523         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1524                 return die_("copying object");
1525         if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1526                 return die_("setting APPLICATION data");
1527         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1528                 return die_("copying object");
1529         if(!FLAC__metadata_iterator_set_block(iterator, app))
1530                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1531
1532         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1533                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1534         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1535                 return false;
1536         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1537                 return false;
1538
1539         printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1540         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1541                 return die_("copying object");
1542         if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1543                 return die_("setting APPLICATION data");
1544         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1545                 return die_("copying object");
1546         if(!FLAC__metadata_iterator_set_block(iterator, app))
1547                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1548
1549         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1550                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1551         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1552                 return false;
1553         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1554                 return false;
1555
1556         printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1557         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1558                 return die_("copying object");
1559         if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1560                 return die_("setting APPLICATION data");
1561         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1562                 return die_("copying object");
1563         if(!FLAC__metadata_iterator_set_block(iterator, app))
1564                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1565
1566         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1567                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1568         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1569                 return false;
1570         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1571                 return false;
1572
1573         printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1574         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1575                 return die_("creating PADDING block");
1576         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1577                 return die_("copying object");
1578         if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1579                 return die_("setting APPLICATION data");
1580         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1581                 return die_("copying object");
1582         padding->length = 0;
1583         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1584                 return die_("internal error");
1585         if(!FLAC__metadata_iterator_set_block(iterator, app))
1586                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1587
1588         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1589                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1590         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1591                 return false;
1592         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1593                 return false;
1594
1595         printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1596         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1597                 return die_("copying object");
1598         if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1599                 return die_("setting APPLICATION data");
1600         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1601                 return die_("copying object");
1602         our_metadata_.blocks[our_current_position+1]->length = 13;
1603         if(!FLAC__metadata_iterator_set_block(iterator, app))
1604                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1605
1606         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1607                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1608         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1609                 return false;
1610         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1611                 return false;
1612
1613         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1614         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1615                 return die_("copying object");
1616         if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1617                 return die_("setting APPLICATION data");
1618         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1619                 return die_("copying object");
1620         if(!FLAC__metadata_iterator_set_block(iterator, app))
1621                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1622
1623         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1624                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1625         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1626                 return false;
1627         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1628                 return false;
1629
1630         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1631         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1632                 return die_("copying object");
1633         if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1634                 return die_("setting APPLICATION data");
1635         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1636                 return die_("copying object");
1637         our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1638         if(!FLAC__metadata_iterator_set_block(iterator, app))
1639                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1640
1641         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1642                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1643         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1644                 return false;
1645         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1646                 return false;
1647
1648         printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1649         if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1650                 return die_("copying object");
1651         if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1652                 return die_("setting APPLICATION data");
1653         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1654                 return die_("copying object");
1655         delete_from_our_metadata_(our_current_position+1);
1656         if(!FLAC__metadata_iterator_set_block(iterator, app))
1657                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1658
1659         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1660                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1661         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1662                 return false;
1663         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1664                 return false;
1665
1666         printf("SV[A]\tprev\n");
1667         if(!FLAC__metadata_iterator_prev(iterator))
1668                 return die_("iterator ended early\n");
1669         our_current_position--;
1670
1671         printf("S[V]A\tprev\n");
1672         if(!FLAC__metadata_iterator_prev(iterator))
1673                 return die_("iterator ended early\n");
1674         our_current_position--;
1675
1676         printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1677         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1678                 return die_("creating PADDING block");
1679         padding->length = 30;
1680         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1681                 printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1682         else
1683                 return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1684
1685         printf("[S]VP\tnext\n");
1686         if(!FLAC__metadata_iterator_next(iterator))
1687                 return die_("iterator ended early\n");
1688         our_current_position++;
1689
1690         printf("S[V]A\tinsert PADDING after\n");
1691         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1692                 return die_("copying metadata");
1693         if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1694                 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1695
1696         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1697                 return false;
1698
1699         printf("SV[P]A\tinsert PADDING before\n");
1700         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1701                 return die_("creating PADDING block");
1702         padding->length = 17;
1703         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1704                 return die_("copying metadata");
1705         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1706                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1707
1708         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1709                 return false;
1710
1711         printf("SV[P]PA\tinsert PADDING before\n");
1712         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1713                 return die_("creating PADDING block");
1714         padding->length = 0;
1715         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1716                 return die_("copying metadata");
1717         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1718                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1719
1720         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1721                 return false;
1722
1723         printf("SV[P]PPA\tnext\n");
1724         if(!FLAC__metadata_iterator_next(iterator))
1725                 return die_("iterator ended early\n");
1726         our_current_position++;
1727
1728         printf("SVP[P]PA\tnext\n");
1729         if(!FLAC__metadata_iterator_next(iterator))
1730                 return die_("iterator ended early\n");
1731         our_current_position++;
1732
1733         printf("SVPP[P]A\tnext\n");
1734         if(!FLAC__metadata_iterator_next(iterator))
1735                 return die_("iterator ended early\n");
1736         our_current_position++;
1737
1738         printf("SVPPP[A]\tinsert PADDING after\n");
1739         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1740                 return die_("creating PADDING block");
1741         padding->length = 57;
1742         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1743                 return die_("copying metadata");
1744         if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1745                 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1746
1747         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1748                 return false;
1749
1750         printf("SVPPPA[P]\tinsert PADDING before\n");
1751         if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1752                 return die_("creating PADDING block");
1753         padding->length = 99;
1754         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1755                 return die_("copying metadata");
1756         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1757                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1758
1759         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1760                 return false;
1761
1762         printf("delete iterator\n");
1763         FLAC__metadata_iterator_delete(iterator);
1764         our_current_position = 0;
1765
1766         printf("SVPPPAPP\tmerge padding\n");
1767         FLAC__metadata_chain_merge_padding(chain);
1768         our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1769         our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
1770         our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
1771         delete_from_our_metadata_(7);
1772         delete_from_our_metadata_(4);
1773         delete_from_our_metadata_(3);
1774
1775         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1776                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1777         if(!compare_chain_(chain, 0, 0))
1778                 return false;
1779         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1780                 return false;
1781
1782         printf("SVPAP\tsort padding\n");
1783         FLAC__metadata_chain_sort_padding(chain);
1784         our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1785         delete_from_our_metadata_(2);
1786
1787         if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfile_))
1788                 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1789         if(!compare_chain_(chain, 0, 0))
1790                 return false;
1791         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1792                 return false;
1793
1794         printf("create iterator\n");
1795         if(0 == (iterator = FLAC__metadata_iterator_new()))
1796                 return die_("allocating memory for iterator");
1797
1798         our_current_position = 0;
1799
1800         FLAC__metadata_iterator_init(iterator, chain);
1801
1802         printf("[S]VAP\tnext\n");
1803         if(!FLAC__metadata_iterator_next(iterator))
1804                 return die_("iterator ended early\n");
1805         our_current_position++;
1806
1807         printf("S[V]AP\tnext\n");
1808         if(!FLAC__metadata_iterator_next(iterator))
1809                 return die_("iterator ended early\n");
1810         our_current_position++;
1811
1812         printf("SV[A]P\tdelete middle block, replace with padding\n");
1813         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1814                 return die_("creating PADDING block");
1815         padding->length = 71;
1816         if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1817                 return die_("copying object");
1818         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1819                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1820
1821         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1822                 return false;
1823
1824         printf("S[V]PP\tnext\n");
1825         if(!FLAC__metadata_iterator_next(iterator))
1826                 return die_("iterator ended early\n");
1827         our_current_position++;
1828
1829         printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1830         delete_from_our_metadata_(our_current_position--);
1831         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1832                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1833
1834         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1835                 return false;
1836
1837         printf("S[V]P\tnext\n");
1838         if(!FLAC__metadata_iterator_next(iterator))
1839                 return die_("iterator ended early\n");
1840         our_current_position++;
1841
1842         printf("SV[P]\tdelete last block, replace with padding\n");
1843         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1844                 return die_("creating PADDING block");
1845         padding->length = 219;
1846         if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1847                 return die_("copying object");
1848         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1849                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1850
1851         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1852                 return false;
1853
1854         printf("S[V]P\tnext\n");
1855         if(!FLAC__metadata_iterator_next(iterator))
1856                 return die_("iterator ended early\n");
1857         our_current_position++;
1858
1859         printf("SV[P]\tdelete last block, don't replace with padding\n");
1860         delete_from_our_metadata_(our_current_position--);
1861         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1862                 return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1863
1864         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1865                 return false;
1866
1867         printf("S[V]\tprev\n");
1868         if(!FLAC__metadata_iterator_prev(iterator))
1869                 return die_("iterator ended early\n");
1870         our_current_position--;
1871
1872         printf("[S]V\tdelete STREAMINFO block, should fail\n");
1873         if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1874                 return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
1875
1876         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1877                 return false;
1878
1879         printf("delete iterator\n");
1880         FLAC__metadata_iterator_delete(iterator);
1881         our_current_position = 0;
1882
1883         printf("SV\tmerge padding\n");
1884         FLAC__metadata_chain_merge_padding(chain);
1885
1886         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1887                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1888         if(!compare_chain_(chain, 0, 0))
1889                 return false;
1890         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1891                 return false;
1892
1893         printf("SV\tsort padding\n");
1894         FLAC__metadata_chain_sort_padding(chain);
1895
1896         if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfile_))
1897                 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1898         if(!compare_chain_(chain, 0, 0))
1899                 return false;
1900         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1901                 return false;
1902
1903         printf("delete chain\n");
1904
1905         FLAC__metadata_chain_delete(chain);
1906
1907         if(!remove_file_(flacfile_))
1908                 return false;
1909
1910         return true;
1911 }
1912
1913 static FLAC__bool test_level_2_misc_()
1914 {
1915         FLAC__Metadata_Iterator *iterator;
1916         FLAC__Metadata_Chain *chain;
1917         FLAC__IOCallbacks callbacks;
1918
1919         memset(&callbacks, 0, sizeof(callbacks));
1920         callbacks.read = (FLAC__IOCallback_Read)fread;
1921 #ifdef FLAC__VALGRIND_TESTING
1922         callbacks.write = chain_write_cb_;
1923 #else
1924         callbacks.write = (FLAC__IOCallback_Write)fwrite;
1925 #endif
1926         callbacks.seek = chain_seek_cb_;
1927         callbacks.tell = chain_tell_cb_;
1928         callbacks.eof = chain_eof_cb_;
1929
1930         printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1931
1932         printf("generate file\n");
1933
1934         if(!generate_file_(/*include_extras=*/false))
1935                 return false;
1936
1937         printf("create chain\n");
1938
1939         if(0 == (chain = FLAC__metadata_chain_new()))
1940                 return die_("allocating chain");
1941
1942         printf("read chain (filename-based)\n");
1943
1944         if(!FLAC__metadata_chain_read(chain, flacfile_))
1945                 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1946
1947         printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
1948         {
1949                 if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
1950                         return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1951                 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1952                         return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1953                 printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1954         }
1955
1956         printf("read chain (filename-based)\n");
1957
1958         if(!FLAC__metadata_chain_read(chain, flacfile_))
1959                 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1960
1961         printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
1962         {
1963                 if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
1964                         return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1965                 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1966                         return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1967                 printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1968         }
1969
1970         printf("read chain (callback-based)\n");
1971         {
1972                 FILE *file = fopen(flacfile_, "rb");
1973                 if(0 == file)
1974                         return die_("opening file");
1975                 if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
1976                         fclose(file);
1977                         return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1978                 }
1979                 fclose(file);
1980         }
1981
1982         printf("write chain with wrong method FLAC__metadata_chain_write()\n");
1983         {
1984                 if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1985                         return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1986                 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1987                         return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1988                 printf("  OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1989         }
1990
1991         printf("read chain (callback-based)\n");
1992         {
1993                 FILE *file = fopen(flacfile_, "rb");
1994                 if(0 == file)
1995                         return die_("opening file");
1996                 if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
1997                         fclose(file);
1998                         return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1999                 }
2000                 fclose(file);
2001         }
2002
2003         printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2004
2005         if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2006                 printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
2007         else
2008                 return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
2009
2010         printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2011         {
2012                 if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2013                         return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2014                 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2015                         return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2016                 printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2017         }
2018
2019         printf("read chain (callback-based)\n");
2020         {
2021                 FILE *file = fopen(flacfile_, "rb");
2022                 if(0 == file)
2023                         return die_("opening file");
2024                 if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2025                         fclose(file);
2026                         return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2027                 }
2028                 fclose(file);
2029         }
2030
2031         printf("create iterator\n");
2032         if(0 == (iterator = FLAC__metadata_iterator_new()))
2033                 return die_("allocating memory for iterator");
2034
2035         FLAC__metadata_iterator_init(iterator, chain);
2036
2037         printf("[S]VP\tnext\n");
2038         if(!FLAC__metadata_iterator_next(iterator))
2039                 return die_("iterator ended early\n");
2040
2041         printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2042         if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
2043                 return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
2044
2045         printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2046
2047         if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2048                 printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
2049         else
2050                 return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
2051
2052         printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
2053         {
2054                 if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
2055                         return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2056                 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2057                         return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2058                 printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2059         }
2060
2061         printf("delete iterator\n");
2062
2063         FLAC__metadata_iterator_delete(iterator);
2064
2065         printf("delete chain\n");
2066
2067         FLAC__metadata_chain_delete(chain);
2068
2069         if(!remove_file_(flacfile_))
2070                 return false;
2071
2072         return true;
2073 }
2074
2075 FLAC__bool test_metadata_file_manipulation()
2076 {
2077         printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
2078
2079         our_metadata_.num_blocks = 0;
2080
2081         if(!test_level_0_())
2082                 return false;
2083
2084         if(!test_level_1_())
2085                 return false;
2086
2087         if(!test_level_2_(/*filename_based=*/true)) /* filename-based */
2088                 return false;
2089         if(!test_level_2_(/*filename_based=*/false)) /* callback-based */
2090                 return false;
2091         if(!test_level_2_misc_())
2092                 return false;
2093
2094         return true;
2095 }