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