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