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