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