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