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