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