b40d3f12fda31a0febe8fdaef3f7c63f29f42d8b
[flac.git] / src / test_unit / metadata_manip.c
1 /* test_unit - Simple FLAC unit tester
2  * Copyright (C) 2002  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 "metadata_utils.h"
20 #include "FLAC/assert.h"
21 #include "FLAC/file_decoder.h"
22 #include "FLAC/metadata.h"
23 #include "FLAC/stream_encoder.h"
24 #include <stdio.h>
25 #include <stdlib.h> /* for malloc() */
26 #include <string.h> /* for memcmp() */
27 #if defined _MSC_VER || defined __MINGW32__
28 #include <io.h> /* for chmod(), unlink */
29 #endif
30 #include <sys/stat.h> /* for stat(), chmod() */
31 #if defined _WIN32 && !defined __CYGWIN__
32 #else
33 #include <unistd.h> /* for unlink() */
34 #endif
35
36 /******************************************************************************
37         The general strategy of these tests (for interface levels 1 and 2) is
38         to create a dummy FLAC file with a known set of initial metadata
39         blocks, then keep a mirror locally of what we expect the metadata to be
40         after each operation.  Then testing becomes a simple matter of running
41         a FLAC__FileDecoder over the dummy file after each operation, comparing
42         the decoded metadata to what's in our local copy.  If there are any
43         differences in the metadata,  or the actual audio data is corrupted, we
44         will catch it while decoding.
45 ******************************************************************************/
46
47 typedef struct {
48         FLAC__bool error_occurred;
49 } decoder_client_struct;
50
51 typedef struct {
52         FILE *file;
53 } encoder_client_struct;
54
55 typedef struct {
56         FLAC__StreamMetaData *blocks[64];
57         unsigned num_blocks;
58 } our_metadata_struct;
59
60 static const char *flacfile_ = "metadata.flac";
61
62 /* our copy of the metadata in flacfile_ */
63 static our_metadata_struct our_metadata_;
64
65 /* the current block number that corresponds to the position of the iterator we are testing */
66 static unsigned mc_our_block_number_ = 0;
67
68 static FLAC__bool die_(const char *msg)
69 {
70         printf("ERROR: %s\n", msg);
71         return false;
72 }
73
74 static FLAC__bool die_c_(const char *msg, FLAC__MetaData_ChainStatus status)
75 {
76         printf("ERROR: %s\n", msg);
77         printf("       status=%s\n", FLAC__MetaData_ChainStatusString[status]);
78         return false;
79 }
80
81 static FLAC__bool die_ss_(const char *msg, FLAC__MetaData_SimpleIterator *siterator)
82 {
83         printf("ERROR: %s\n", msg);
84         printf("       status=%s\n", FLAC__MetaData_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(siterator)]);
85         return false;
86 }
87
88 /* functions for working with our metadata copy */
89
90 static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetaData *block, unsigned position, FLAC__bool copy)
91 {
92         unsigned i;
93         FLAC__StreamMetaData *obj = block;
94         FLAC__ASSERT(position < our_metadata_.num_blocks);
95         if(copy) {
96                 if(0 == (obj = FLAC__metadata_object_copy(block)))
97                         return die_("during FLAC__metadata_object_copy()");
98         }
99         FLAC__metadata_object_delete(our_metadata_.blocks[position]);
100         our_metadata_.blocks[position] = obj;
101
102         /* set the is_last flags */
103         for(i = 0; i < our_metadata_.num_blocks - 1; i++)
104                 our_metadata_.blocks[i]->is_last = false;
105         our_metadata_.blocks[i]->is_last = true;
106
107         return true;
108 }
109
110 static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetaData *block, unsigned position, FLAC__bool copy)
111 {
112         unsigned i;
113         FLAC__StreamMetaData *obj = block;
114         if(copy) {
115                 if(0 == (obj = FLAC__metadata_object_copy(block)))
116                         return die_("during FLAC__metadata_object_copy()");
117         }
118         if(position > our_metadata_.num_blocks) {
119                 position = our_metadata_.num_blocks;
120         }
121         else {
122                 for(i = our_metadata_.num_blocks; i > position; i--)
123                         our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
124         }
125         our_metadata_.blocks[position] = obj;
126         our_metadata_.num_blocks++;
127
128         /* set the is_last flags */
129         for(i = 0; i < our_metadata_.num_blocks - 1; i++)
130                 our_metadata_.blocks[i]->is_last = false;
131         our_metadata_.blocks[i]->is_last = true;
132
133         return true;
134 }
135
136 static void delete_from_our_metadata_(unsigned position)
137 {
138         unsigned i;
139         FLAC__ASSERT(position < our_metadata_.num_blocks);
140         FLAC__metadata_object_delete(our_metadata_.blocks[position]);
141         for(i = position; i < our_metadata_.num_blocks - 1; i++)
142                 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
143         our_metadata_.num_blocks--;
144
145         /* set the is_last flags */
146         if(our_metadata_.num_blocks > 0) {
147                 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
148                         our_metadata_.blocks[i]->is_last = false;
149                 our_metadata_.blocks[i]->is_last = true;
150         }
151 }
152
153 /* function for comparing our metadata to a FLAC__MetaData_Chain */
154
155 static FLAC__bool compare_chain_(FLAC__MetaData_Chain *chain, unsigned current_position, FLAC__StreamMetaData *current_block)
156 {
157         unsigned i;
158         FLAC__MetaData_Iterator *iterator;
159         FLAC__StreamMetaData *block;
160         FLAC__bool next_ok = true;
161
162         FLAC__ASSERT(0 != chain);
163
164         printf("\tcomparing chain... ");
165         fflush(stdout);
166
167         if(0 == (iterator = FLAC__metadata_iterator_new()))
168                 return die_("allocating memory for iterator");
169
170         FLAC__metadata_iterator_init(iterator, chain);
171
172         i = 0;
173         do {
174                 printf("%u... ", i);
175                 fflush(stdout);
176
177                 if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
178                         FLAC__metadata_iterator_delete(iterator);
179                         return die_("getting block from iterator");
180                 }
181
182                 if(!compare_block_(our_metadata_.blocks[i], block)) {
183                         FLAC__metadata_iterator_delete(iterator);
184                         return die_("metadata block mismatch");
185                 }
186
187                 i++;
188                 next_ok = FLAC__metadata_iterator_next(iterator);
189         } while(i < our_metadata_.num_blocks && next_ok);
190
191         FLAC__metadata_iterator_delete(iterator);
192
193         if(next_ok)
194                 return die_("chain has more blocks than expected");
195
196         if(i < our_metadata_.num_blocks)
197                 return die_("short block count in chain");
198
199         if(0 != current_block) {
200                 printf("CURRENT_POSITION... ");
201                 fflush(stdout);
202
203                 if(!compare_block_(our_metadata_.blocks[current_position], current_block))
204                         return die_("metadata block mismatch");
205         }
206
207         printf("PASSED\n");
208
209         return true;
210 }
211
212 /* decoder callbacks for checking the file */
213
214 static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
215 {
216         (void)decoder, (void)buffer, (void)client_data;
217
218         if(
219                 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
220                 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
221         ) {
222                 printf("content... ");
223                 fflush(stdout);
224         }
225
226         return FLAC__STREAM_DECODER_WRITE_CONTINUE;
227 }
228
229 static void decoder_error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
230 {
231         decoder_client_struct *dcd = (decoder_client_struct*)client_data;
232         (void)decoder;
233
234         dcd->error_occurred = true;
235         printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
236 }
237
238 /* this version pays no attention to the metadata */
239 static void decoder_metadata_callback_null_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
240 {
241         (void)decoder, (void)metadata, (void)client_data;
242
243         printf("%d... ", mc_our_block_number_);
244         fflush(stdout);
245
246         mc_our_block_number_++;
247 }
248
249 /* this version is used when we want to compare to our metadata copy */
250 static void decoder_metadata_callback_compare_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
251 {
252         decoder_client_struct *dcd = (decoder_client_struct*)client_data;
253
254         (void)decoder;
255
256         /* don't bother checking if we've already hit an error */
257         if(dcd->error_occurred)
258                 return;
259
260         printf("%d... ", mc_our_block_number_);
261         fflush(stdout);
262
263         if(mc_our_block_number_ >= our_metadata_.num_blocks) {
264                 (void)die_("got more metadata blocks than expected");
265                 dcd->error_occurred = true;
266         }
267         else {
268                 if(!compare_block_(our_metadata_.blocks[mc_our_block_number_], metadata)) {
269                         (void)die_("metadata block mismatch");
270                         dcd->error_occurred = true;
271                 }
272         }
273         mc_our_block_number_++;
274 }
275
276 static FLAC__StreamEncoderWriteStatus encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
277 {
278         encoder_client_struct *ecd = (encoder_client_struct*)client_data;
279
280         (void)encoder, (void)samples, (void)current_frame;
281
282         if(fwrite(buffer, 1, bytes, ecd->file) != bytes)
283                 return FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR;
284         else
285                 return FLAC__STREAM_ENCODER_WRITE_OK;
286 }
287
288 static void encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data)
289 {
290         (void)encoder, (void)metadata, (void)client_data;
291 }
292
293 static FLAC__bool generate_file_(const char *input_filename)
294 {
295         FLAC__StreamEncoder *encoder;
296         FLAC__StreamMetaData streaminfo, padding;
297         encoder_client_struct encoder_client_data;
298         FILE *file;
299         FLAC__byte buffer[4096];
300         FLAC__int32 samples[4096];
301         unsigned i, n;
302
303         FLAC__ASSERT(0 != input_filename);
304
305         printf("generating FLAC file for test\n");
306
307         while(our_metadata_.num_blocks > 0)
308                 delete_from_our_metadata_(0);
309
310         streaminfo.is_last = false;
311         streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
312         streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
313         streaminfo.data.stream_info.min_blocksize = 576;
314         streaminfo.data.stream_info.max_blocksize = 576;
315         streaminfo.data.stream_info.min_framesize = 0;
316         streaminfo.data.stream_info.max_framesize = 0;
317         streaminfo.data.stream_info.sample_rate = 44100;
318         streaminfo.data.stream_info.channels = 1;
319         streaminfo.data.stream_info.bits_per_sample = 8;
320         streaminfo.data.stream_info.total_samples = 0;
321         memset(streaminfo.data.stream_info.md5sum, 0, 16);
322
323         padding.is_last = true;
324         padding.type = FLAC__METADATA_TYPE_PADDING;
325         padding.length = 1234;
326
327         if(!insert_to_our_metadata_(&streaminfo, 0, /*copy=*/true) || !insert_to_our_metadata_(&padding, 1, /*copy=*/true))
328                 return die_("priming our metadata");
329
330         if(0 == (file = fopen(input_filename, "rb")))
331                 return die_("opening input file");
332         if(0 == (encoder_client_data.file = fopen(flacfile_, "wb"))) {
333                 fclose(file);
334                 return die_("opening output file");
335         }
336
337         encoder = FLAC__stream_encoder_new();
338         if(0 == encoder) {
339                 fclose(file);
340                 fclose(encoder_client_data.file);
341                 return die_("creating the encoder instance"); 
342         }
343
344         FLAC__stream_encoder_set_streamable_subset(encoder, true);
345         FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false);
346         FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false);
347         FLAC__stream_encoder_set_channels(encoder, streaminfo.data.stream_info.channels);
348         FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo.data.stream_info.bits_per_sample);
349         FLAC__stream_encoder_set_sample_rate(encoder, streaminfo.data.stream_info.sample_rate);
350         FLAC__stream_encoder_set_blocksize(encoder, streaminfo.data.stream_info.min_blocksize);
351         FLAC__stream_encoder_set_max_lpc_order(encoder, 0);
352         FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0);
353         FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false);
354         FLAC__stream_encoder_set_do_escape_coding(encoder, false);
355         FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false);
356         FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0);
357         FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0);
358         FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0);
359         FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo.data.stream_info.total_samples);
360         FLAC__stream_encoder_set_seek_table(encoder, 0);
361         FLAC__stream_encoder_set_padding(encoder, padding.length);
362         FLAC__stream_encoder_set_last_metadata_is_last(encoder, true);
363         FLAC__stream_encoder_set_write_callback(encoder, encoder_write_callback_);
364         FLAC__stream_encoder_set_metadata_callback(encoder, encoder_metadata_callback_);
365         FLAC__stream_encoder_set_client_data(encoder, &encoder_client_data);
366
367         if(FLAC__stream_encoder_init(encoder) != FLAC__STREAM_ENCODER_OK) {
368                 fclose(file);
369                 fclose(encoder_client_data.file);
370                 return die_("initializing encoder");
371         }
372
373         while(!feof(file)) {
374                 n = fread(buffer, 1, sizeof(buffer), file);
375                 if(n > 0) {
376                         for(i = 0; i < n; i++)
377                                 samples[i] = (FLAC__int32)((signed char)buffer[i]);
378
379                         /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
380                         if(!FLAC__stream_encoder_process_interleaved(encoder, samples, n)) {
381                                 fclose(file);
382                                 fclose(encoder_client_data.file);
383                                 return die_("during encoding");
384                         }
385                 }
386                 else if(!feof(file)) {
387                         fclose(file);
388                         fclose(encoder_client_data.file);
389                         return die_("reading input file");
390                 }
391         }
392
393         fclose(file);
394         fclose(encoder_client_data.file);
395
396         if(FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK)
397                 FLAC__stream_encoder_finish(encoder);
398         FLAC__stream_encoder_delete(encoder);
399
400         return true;
401 }
402
403 static FLAC__bool test_file_(const char *filename, void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data))
404 {
405         FLAC__FileDecoder *decoder;
406         decoder_client_struct decoder_client_data;
407
408         FLAC__ASSERT(0 != filename);
409         FLAC__ASSERT(0 != metadata_callback);
410
411         mc_our_block_number_ = 0;
412         decoder_client_data.error_occurred = false;
413
414         printf("\ttesting '%s'... ", filename);
415         fflush(stdout);
416
417         if(0 == (decoder = FLAC__file_decoder_new()))
418                 return die_("couldn't allocate memory");
419
420         FLAC__file_decoder_set_md5_checking(decoder, true);
421         FLAC__file_decoder_set_filename(decoder, filename);
422         FLAC__file_decoder_set_write_callback(decoder, decoder_write_callback_);
423         FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
424         FLAC__file_decoder_set_error_callback(decoder, decoder_error_callback_);
425         FLAC__file_decoder_set_client_data(decoder, &decoder_client_data);
426         FLAC__file_decoder_set_metadata_respond_all(decoder);
427         if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
428                 FLAC__file_decoder_finish(decoder);
429                 FLAC__file_decoder_delete(decoder);
430                 return die_("initializing decoder\n");
431         }
432         if(!FLAC__file_decoder_process_whole_file(decoder)) {
433                 FLAC__file_decoder_finish(decoder);
434                 FLAC__file_decoder_delete(decoder);
435                 return die_("decoding file\n");
436         }
437
438         FLAC__file_decoder_finish(decoder);
439         FLAC__file_decoder_delete(decoder);
440
441         if(decoder_client_data.error_occurred)
442                 return false;
443
444         if(mc_our_block_number_ != our_metadata_.num_blocks)
445                 return die_("short metadata block count");
446
447         printf("PASSED\n");
448         return true;
449 }
450
451 static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
452 {
453         struct stat stats;
454
455         if(0 == stat(filename, &stats)) {
456                 if(read_only) {
457                         stats.st_mode &= ~S_IWUSR;
458                         stats.st_mode &= ~S_IWGRP;
459                         stats.st_mode &= ~S_IWOTH;
460                 }
461                 else {
462                         stats.st_mode |= S_IWUSR;
463                         stats.st_mode |= S_IWGRP;
464                         stats.st_mode |= S_IWOTH;
465                 }
466                 if(0 != chmod(filename, stats.st_mode))
467                         return die_("during chmod()");
468         }
469         else
470                 return die_("during stat()");
471
472         return true;
473 }
474
475 static FLAC__bool remove_file_(const char *filename)
476 {
477         while(our_metadata_.num_blocks > 0)
478                 delete_from_our_metadata_(0);
479
480         if(!change_stats_(filename, /*read_only=*/false) || 0 != unlink(filename))
481                 return die_("removing file");
482
483         return true;
484 }
485
486 static FLAC__bool test_level_0_(const char *progname)
487 {
488         FLAC__StreamMetaData_StreamInfo streaminfo;
489
490         printf("\n\n++++++ testing level 0 interface\n");
491
492         if(!generate_file_(progname))
493                 return false;
494
495         if(!test_file_(flacfile_, decoder_metadata_callback_null_))
496                 return false;
497
498         if(!FLAC__metadata_get_streaminfo(flacfile_, &streaminfo))
499                 return die_("during FLAC__metadata_get_streaminfo()");
500
501         /* check to see if some basic data matches (c.f. generate_file_()) */
502         if(streaminfo.channels != 1)
503                 return die_("mismatch in streaminfo.channels");
504         if(streaminfo.bits_per_sample != 8)
505                 return die_("mismatch in streaminfo.bits_per_sample");
506         if(streaminfo.sample_rate != 44100)
507                 return die_("mismatch in streaminfo.sample_rate");
508         if(streaminfo.min_blocksize != 576)
509                 return die_("mismatch in streaminfo.min_blocksize");
510         if(streaminfo.max_blocksize != 576)
511                 return die_("mismatch in streaminfo.max_blocksize");
512
513         if(!remove_file_(flacfile_))
514                 return false;
515
516         return true;
517 }
518
519 static FLAC__bool test_level_1_(const char *progname)
520 {
521         FLAC__MetaData_SimpleIterator *siterator;
522         FLAC__StreamMetaData *block, *app, *padding;
523         FLAC__byte data[1000];
524         unsigned our_current_position = 0;
525
526         printf("\n\n++++++ testing level 1 interface\n");
527
528         /************************************************************/
529
530         printf("simple iterator on read-only file\n");
531
532         if(!generate_file_(progname))
533                 return false;
534
535         if(!change_stats_(flacfile_, /*read_only=*/true))
536                 return false;
537
538         if(!test_file_(flacfile_, decoder_metadata_callback_null_))
539                 return false;
540
541         if(0 == (siterator = FLAC__metadata_simple_iterator_new()))
542                 return die_("FLAC__metadata_simple_iterator_new()");
543
544         if(!FLAC__metadata_simple_iterator_init(siterator, flacfile_, false))
545                 return die_("ERROR: FLAC__metadata_simple_iterator_init()\n");
546
547         printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(siterator));
548         if(FLAC__metadata_simple_iterator_is_writable(siterator))
549                 return die_("iterator claims file is writable when it should not be\n");
550
551         printf("iterate forwards\n");
552
553         if(FLAC__metadata_simple_iterator_get_block_type(siterator) != FLAC__METADATA_TYPE_STREAMINFO)
554                 return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
555         if(0 == (block = FLAC__metadata_simple_iterator_get_block(siterator)))
556                 return die_("getting block 0");
557         if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
558                 return die_("expected STREAMINFO type");
559         if(block->is_last)
560                 return die_("expected is_last to be false");
561         if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
562                 return die_("bad STREAMINFO length");
563         /* check to see if some basic data matches (c.f. generate_file_()) */
564         if(block->data.stream_info.channels != 1)
565                 return die_("mismatch in channels");
566         if(block->data.stream_info.bits_per_sample != 8)
567                 return die_("mismatch in bits_per_sample");
568         if(block->data.stream_info.sample_rate != 44100)
569                 return die_("mismatch in sample_rate");
570         if(block->data.stream_info.min_blocksize != 576)
571                 return die_("mismatch in min_blocksize");
572         if(block->data.stream_info.max_blocksize != 576)
573                 return die_("mismatch in max_blocksize");
574
575         if(!FLAC__metadata_simple_iterator_next(siterator))
576                 return die_("forward iterator ended early");
577         our_current_position++;
578
579         if(FLAC__metadata_simple_iterator_get_block_type(siterator) != FLAC__METADATA_TYPE_PADDING)
580                 return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
581         if(0 == (block = FLAC__metadata_simple_iterator_get_block(siterator)))
582                 return die_("getting block 1");
583         if(block->type != FLAC__METADATA_TYPE_PADDING)
584                 return die_("expected PADDING type");
585         if(!block->is_last)
586                 return die_("expected is_last to be true");
587         /* check to see if some basic data matches (c.f. generate_file_()) */
588         if(block->length != 1234)
589                 return die_("bad STREAMINFO length");
590
591         if(FLAC__metadata_simple_iterator_next(siterator))
592                 return die_("forward iterator returned true but should have returned false");
593
594         printf("iterate backwards\n");
595         if(!FLAC__metadata_simple_iterator_prev(siterator))
596                 return die_("reverse iterator ended early");
597         if(FLAC__metadata_simple_iterator_prev(siterator))
598                 return die_("reverse iterator returned true but should have returned false");
599
600         printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
601
602         if(!FLAC__metadata_simple_iterator_set_block(siterator, (void*)99, false))
603                 printf("PASSED.  FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
604         else
605                 return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
606
607         FLAC__metadata_simple_iterator_delete(siterator);
608
609         /************************************************************/
610
611         printf("simple iterator on writable file\n");
612
613         if(!change_stats_(flacfile_, /*read-only=*/false))
614                 return false;
615
616         printf("creating APPLICATION block\n");
617
618         if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
619                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
620         memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
621
622         printf("creating PADDING block\n");
623
624         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
625                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
626         padding->length = 20;
627
628         if(0 == (siterator = FLAC__metadata_simple_iterator_new()))
629                 return die_("FLAC__metadata_simple_iterator_new()");
630
631         if(!FLAC__metadata_simple_iterator_init(siterator, flacfile_, /*preserve_file_stats=*/false))
632                 return die_("ERROR: FLAC__metadata_simple_iterator_init()\n");
633         our_current_position = 0;
634
635         printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(siterator));
636
637         printf("[S]P\ttry to write over STREAMINFO block...\n");
638         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
639                 printf("FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
640         else
641                 return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
642
643         printf("[S]P\tnext\n");
644         if(!FLAC__metadata_simple_iterator_next(siterator))
645                 return die_("iterator ended early\n");
646         our_current_position++;
647
648         printf("S[P]\tinsert PADDING after, don't expand into padding\n");
649         padding->length = 25;
650         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
651                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
652         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
653                 return false;
654
655         printf("SP[P]\tprev\n");
656         if(!FLAC__metadata_simple_iterator_prev(siterator))
657                 return die_("iterator ended early\n");
658         our_current_position--;
659
660         printf("S[P]P\tprev\n");
661         if(!FLAC__metadata_simple_iterator_prev(siterator))
662                 return die_("iterator ended early\n");
663         our_current_position--;
664
665         printf("[S]PP\tinsert PADDING after, don't expand into padding\n");
666         padding->length = 30;
667         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
668                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
669         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
670                 return false;
671
672         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
673                 return false;
674         
675         printf("S[P]PP\tprev\n");
676         if(!FLAC__metadata_simple_iterator_prev(siterator))
677                 return die_("iterator ended early\n");
678         our_current_position--;
679
680         printf("[S]PPP\tdelete (STREAMINFO block), must fail\n");
681         if(FLAC__metadata_simple_iterator_delete_block(siterator, false))
682                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false) should have returned false", siterator);
683
684         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
685                 return false;
686
687         printf("[S]PPP\tnext\n");
688         if(!FLAC__metadata_simple_iterator_next(siterator))
689                 return die_("iterator ended early\n");
690         our_current_position++;
691
692         printf("S[P]PP\tdelete (middle block), replace with padding\n");
693         if(!FLAC__metadata_simple_iterator_delete_block(siterator, true))
694                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, true)", siterator);
695         our_current_position--;
696
697         printf("[S]PPP\tnext\n");
698         if(!FLAC__metadata_simple_iterator_next(siterator))
699                 return die_("iterator ended early\n");
700         our_current_position++;
701
702         printf("S[P]PP\tdelete (middle block), don't replace with padding\n");
703         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
704                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
705         delete_from_our_metadata_(our_current_position--);
706
707         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
708                 return false;
709
710         printf("[S]PP\tnext\n");
711         if(!FLAC__metadata_simple_iterator_next(siterator))
712                 return die_("iterator ended early\n");
713         our_current_position++;
714
715         printf("S[P]P\tnext\n");
716         if(!FLAC__metadata_simple_iterator_next(siterator))
717                 return die_("iterator ended early\n");
718         our_current_position++;
719
720         printf("SP[P]\tdelete (last block), replace with padding\n");
721         if(!FLAC__metadata_simple_iterator_delete_block(siterator, true))
722                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
723         our_current_position--;
724
725         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
726                 return false;
727
728         printf("S[P]P\tnext\n");
729         if(!FLAC__metadata_simple_iterator_next(siterator))
730                 return die_("iterator ended early\n");
731         our_current_position++;
732
733         printf("SP[P]\tdelete (last block), don't replace with padding\n");
734         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
735                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
736         delete_from_our_metadata_(our_current_position--);
737
738         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
739                 return false;
740
741         printf("S[P]\tprev\n");
742         if(!FLAC__metadata_simple_iterator_prev(siterator))
743                 return die_("iterator ended early\n");
744         our_current_position--;
745
746         printf("[S]P\tset STREAMINFO (change sample rate)\n");
747         FLAC__ASSERT(our_current_position == 0);
748         block = FLAC__metadata_simple_iterator_get_block(siterator);
749         block->data.stream_info.sample_rate = 32000;
750         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
751                 return die_("copying object");
752         if(!FLAC__metadata_simple_iterator_set_block(siterator, block, false))
753                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, block, false)", siterator);
754         FLAC__metadata_object_delete(block);
755
756         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
757                 return false;
758
759         printf("[S]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
760         app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
761         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
762                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
763         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
764                 return false;
765         our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
766
767         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
768                 return false;
769
770         printf("S[A]P\tnext\n");
771         if(!FLAC__metadata_simple_iterator_next(siterator))
772                 return die_("iterator ended early\n");
773         our_current_position++;
774
775         printf("SA[P]\tset APPLICATION, expand into padding of exceeding size\n");
776         app->data.application.id[0] = 'f'; /* twiddle the id */
777         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
778                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
779         if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
780                 return false;
781         our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
782
783         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
784                 return false;
785
786         printf("SA[A]P\tset APPLICATION (grow), don't expand into padding\n");
787         app->data.application.id[0] = 'g'; /* twiddle the id */
788         if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
789                 return die_("setting APPLICATION data");
790         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
791                 return die_("copying object");
792         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
793                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, false)", siterator);
794
795         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
796                 return false;
797
798         printf("SA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
799         app->data.application.id[0] = 'h'; /* twiddle the id */
800         if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
801                 return die_("setting APPLICATION data");
802         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
803                 return die_("copying object");
804         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
805                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, false)", siterator);
806
807         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
808                 return false;
809
810         printf("SA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
811         app->data.application.id[0] = 'i'; /* twiddle the id */
812         if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
813                 return die_("setting APPLICATION data");
814         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
815                 return die_("copying object");
816         our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
817         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
818                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
819
820         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
821                 return false;
822
823         printf("SA[A]P\tset APPLICATION (shrink), fill in with padding\n");
824         app->data.application.id[0] = 'j'; /* twiddle the id */
825         if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
826                 return die_("setting APPLICATION data");
827         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
828                 return die_("copying object");
829         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
830                 return die_("copying object");
831         our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - 4;
832         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
833                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
834
835         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
836                 return false;
837
838         printf("SA[A]PP\tnext\n");
839         if(!FLAC__metadata_simple_iterator_next(siterator))
840                 return die_("iterator ended early\n");
841         our_current_position++;
842
843         printf("SAA[P]P\tnext\n");
844         if(!FLAC__metadata_simple_iterator_next(siterator))
845                 return die_("iterator ended early\n");
846         our_current_position++;
847
848         printf("SAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
849         padding->length = 5;
850         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
851                 return die_("copying object");
852         if(!FLAC__metadata_simple_iterator_set_block(siterator, padding, false))
853                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, padding, false)", siterator);
854
855         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
856                 return false;
857
858         printf("SAAP[P]\tset APPLICATION (grow)\n");
859         app->data.application.id[0] = 'k'; /* twiddle the id */
860         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
861                 return die_("copying object");
862         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
863                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, false)", siterator);
864
865         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
866                 return false;
867
868         printf("SAAP[A]\tset PADDING (equal)\n");
869         padding->length = 27;
870         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
871                 return die_("copying object");
872         if(!FLAC__metadata_simple_iterator_set_block(siterator, padding, false))
873                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, padding, false)", siterator);
874
875         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
876                 return false;
877
878         printf("SAAP[P]\tprev\n");
879         if(!FLAC__metadata_simple_iterator_prev(siterator))
880                 return die_("iterator ended early\n");
881         our_current_position--;
882
883         printf("SAA[P]P\tdelete (middle block), don't replace with padding\n");
884         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
885                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
886         delete_from_our_metadata_(our_current_position--);
887
888         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
889                 return false;
890
891         printf("SA[A]P\tdelete (middle block), don't replace with padding\n");
892         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
893                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
894         delete_from_our_metadata_(our_current_position--);
895
896         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
897                 return false;
898
899         printf("S[A]P\tnext\n");
900         if(!FLAC__metadata_simple_iterator_next(siterator))
901                 return die_("iterator ended early\n");
902         our_current_position++;
903
904         printf("SA[P]\tinsert PADDING after\n");
905         padding->length = 5;
906         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
907                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
908         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
909                 return false;
910
911         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
912                 return false;
913
914         printf("SAP[P]\tprev\n");
915         if(!FLAC__metadata_simple_iterator_prev(siterator))
916                 return die_("iterator ended early\n");
917         our_current_position--;
918
919         printf("SA[P]P\tprev\n");
920         if(!FLAC__metadata_simple_iterator_prev(siterator))
921                 return die_("iterator ended early\n");
922         our_current_position--;
923
924         printf("S[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
925         if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
926                 return die_("setting APPLICATION data");
927         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
928                 return die_("copying object");
929         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
930                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
931
932         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
933                 return false;
934
935         printf("S[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
936         if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
937                 return die_("setting APPLICATION data");
938         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
939                 return die_("copying object");
940         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
941                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
942
943         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
944                 return false;
945
946         printf("S[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
947         if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
948                 return die_("setting APPLICATION data");
949         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
950                 return die_("copying object");
951         our_metadata_.blocks[our_current_position+1]->length = 0;
952         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
953                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
954
955         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
956                 return false;
957
958         printf("S[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
959         if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
960                 return die_("setting APPLICATION data");
961         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
962                 return die_("copying object");
963         delete_from_our_metadata_(our_current_position+1);
964         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
965                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
966
967         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
968                 return false;
969
970         printf("S[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
971         if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
972                 return die_("setting APPLICATION data");
973         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
974                 return die_("copying object");
975         delete_from_our_metadata_(our_current_position+1);
976         our_metadata_.blocks[our_current_position]->is_last = true;
977         if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
978                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
979
980         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
981                 return false;
982
983         printf("S[A]\tset PADDING (equal size)\n");
984         padding->length = app->length;
985         if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
986                 return die_("copying object");
987         if(!FLAC__metadata_simple_iterator_set_block(siterator, padding, true))
988                 return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, padding, true)", siterator);
989
990         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
991                 return false;
992
993         printf("S[P]\tinsert PADDING after\n");
994         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
995                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
996         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
997                 return false;
998
999         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1000                 return false;
1001
1002         printf("SP[P]\tinsert PADDING after\n");
1003         padding->length = 5;
1004         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
1005                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
1006         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1007                 return false;
1008
1009         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1010                 return false;
1011
1012         printf("SPP[P]\tprev\n");
1013         if(!FLAC__metadata_simple_iterator_prev(siterator))
1014                 return die_("iterator ended early\n");
1015         our_current_position--;
1016
1017         printf("SP[P]P\tprev\n");
1018         if(!FLAC__metadata_simple_iterator_prev(siterator))
1019                 return die_("iterator ended early\n");
1020         our_current_position--;
1021
1022         printf("S[P]PP\tprev\n");
1023         if(!FLAC__metadata_simple_iterator_prev(siterator))
1024                 return die_("iterator ended early\n");
1025         our_current_position--;
1026
1027         printf("[S]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1028         if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1029                 return die_("setting APPLICATION data");
1030         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1031                 return die_("copying object");
1032         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
1033                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
1034
1035         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1036                 return false;
1037
1038         printf("S[A]PPP\tdelete (middle block), don't replace with padding\n");
1039         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
1040                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
1041         delete_from_our_metadata_(our_current_position--);
1042
1043         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1044                 return false;
1045
1046         printf("[S]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1047         if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1048                 return die_("setting APPLICATION data");
1049         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1050                 return die_("copying object");
1051         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
1052                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
1053
1054         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1055                 return false;
1056
1057         printf("S[A]PPP\tdelete (middle block), don't replace with padding\n");
1058         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
1059                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
1060         delete_from_our_metadata_(our_current_position--);
1061
1062         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1063                 return false;
1064
1065         printf("[S]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1066         if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1067                 return die_("setting APPLICATION data");
1068         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1069                 return die_("copying object");
1070         delete_from_our_metadata_(our_current_position+1);
1071         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
1072                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
1073
1074         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1075                 return false;
1076
1077         printf("S[A]PP\tdelete (middle block), don't replace with padding\n");
1078         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
1079                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
1080         delete_from_our_metadata_(our_current_position--);
1081
1082         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1083                 return false;
1084
1085         printf("[S]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1086         if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1087                 return die_("setting APPLICATION data");
1088         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1089                 return die_("copying object");
1090         our_metadata_.blocks[our_current_position+1]->length = 0;
1091         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
1092                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
1093
1094         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1095                 return false;
1096
1097         printf("S[A]PP\tdelete (middle block), don't replace with padding\n");
1098         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
1099                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
1100         delete_from_our_metadata_(our_current_position--);
1101
1102         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1103                 return false;
1104
1105         printf("[S]PP\tnext\n");
1106         if(!FLAC__metadata_simple_iterator_next(siterator))
1107                 return die_("iterator ended early\n");
1108         our_current_position++;
1109
1110         printf("S[P]P\tdelete (middle block), don't replace with padding\n");
1111         if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
1112                 return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
1113         delete_from_our_metadata_(our_current_position--);
1114
1115         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1116                 return false;
1117
1118         printf("[S]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1119         if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1120                 return die_("setting APPLICATION data");
1121         if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1122                 return die_("copying object");
1123         delete_from_our_metadata_(our_current_position+1);
1124         if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
1125                 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
1126
1127         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1128                 return false;
1129
1130         printf("delete simple iterator\n");
1131
1132         FLAC__metadata_simple_iterator_delete(siterator);
1133
1134         FLAC__metadata_object_delete(app);
1135         FLAC__metadata_object_delete(padding);
1136
1137         if(!remove_file_(flacfile_))
1138                 return false;
1139
1140         return true;
1141 }
1142
1143 static FLAC__bool test_level_2_(const char *progname)
1144 {
1145         FLAC__MetaData_Iterator *iterator;
1146         FLAC__MetaData_Chain *chain;
1147         FLAC__StreamMetaData *block, *app, *padding;
1148         FLAC__byte data[2000];
1149         unsigned our_current_position;
1150
1151         printf("\n\n++++++ testing level 2 interface\n");
1152
1153         printf("generate read-only file\n");
1154
1155         if(!generate_file_(progname))
1156                 return false;
1157
1158         if(!change_stats_(flacfile_, /*read_only=*/true))
1159                 return false;
1160
1161         printf("create chain\n");
1162
1163         if(0 == (chain = FLAC__metadata_chain_new()))
1164                 return die_("allocating chain");
1165
1166         printf("read chain\n");
1167
1168         if(!FLAC__metadata_chain_read(chain, flacfile_))
1169                 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1170
1171         printf("[S]P\ttest initial metadata\n");
1172
1173         if(!compare_chain_(chain, 0, 0))
1174                 return false;
1175         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1176                 return false;
1177
1178         printf("switch file to read-write\n");
1179
1180         if(!change_stats_(flacfile_, /*read-only=*/false))
1181                 return false;
1182
1183         printf("[S]P\tmodify STREAMINFO, write\n");
1184
1185         if(0 == (iterator = FLAC__metadata_iterator_new()))
1186                 return die_("allocating memory for iterator");
1187
1188         our_current_position = 0;
1189
1190         FLAC__metadata_iterator_init(iterator, chain);
1191
1192         if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1193                 return die_("getting block from iterator");
1194
1195         FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1196
1197         block->data.stream_info.sample_rate = 32000;
1198         if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1199                 return die_("copying object");
1200
1201         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/true))
1202                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1203         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1204                 return false;
1205         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1206                 return false;
1207
1208         printf("[S]P\tnext\n");
1209         if(!FLAC__metadata_iterator_next(iterator))
1210                 return die_("iterator ended early\n");
1211         our_current_position++;
1212
1213         printf("S[P]\treplace PADDING with identical-size APPLICATION\n");
1214         if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1215                 return die_("getting block from iterator");
1216         if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1217                 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1218         memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1219         if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1220                 return die_("setting APPLICATION data");
1221         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1222                 return die_("copying object");
1223         if(!FLAC__metadata_iterator_set_block(iterator, app))
1224                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1225
1226         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1227                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1228         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1229                 return false;
1230         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1231                 return false;
1232
1233         printf("S[A]\tshrink APPLICATION, don't use padding\n");
1234         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1235                 return die_("copying object");
1236         if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1237                 return die_("setting APPLICATION data");
1238         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1239                 return die_("copying object");
1240         if(!FLAC__metadata_iterator_set_block(iterator, app))
1241                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1242
1243         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1244                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1245         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1246                 return false;
1247         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1248                 return false;
1249
1250         printf("S[A]\tgrow APPLICATION, don't use padding\n");
1251         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1252                 return die_("copying object");
1253         if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1254                 return die_("setting APPLICATION data");
1255         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1256                 return die_("copying object");
1257         if(!FLAC__metadata_iterator_set_block(iterator, app))
1258                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1259
1260         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1261                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1262         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1263                 return false;
1264         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1265                 return false;
1266
1267         printf("S[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1268         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1269                 return die_("copying object");
1270         if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1271                 return die_("setting APPLICATION data");
1272         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1273                 return die_("copying object");
1274         if(!FLAC__metadata_iterator_set_block(iterator, app))
1275                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1276
1277         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
1278                 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1279         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1280                 return false;
1281         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1282                 return false;
1283
1284         printf("S[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1285         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1286                 return die_("copying object");
1287         if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1288                 return die_("setting APPLICATION data");
1289         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1290                 return die_("copying object");
1291         if(!FLAC__metadata_iterator_set_block(iterator, app))
1292                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1293
1294         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1295                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1296         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1297                 return false;
1298         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1299                 return false;
1300
1301         printf("S[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1302         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1303                 return die_("creating PADDING block");
1304         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1305                 return die_("copying object");
1306         if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1307                 return die_("setting APPLICATION data");
1308         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1309                 return die_("copying object");
1310         padding->length = 0;
1311         if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1312                 return die_("internal error");
1313         if(!FLAC__metadata_iterator_set_block(iterator, app))
1314                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1315
1316         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1317                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1318         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1319                 return false;
1320         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1321                 return false;
1322
1323         printf("S[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1324         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1325                 return die_("copying object");
1326         if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1327                 return die_("setting APPLICATION data");
1328         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1329                 return die_("copying object");
1330         our_metadata_.blocks[our_current_position+1]->length = 13;
1331         if(!FLAC__metadata_iterator_set_block(iterator, app))
1332                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1333
1334         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1335                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1336         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1337                 return false;
1338         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1339                 return false;
1340
1341         printf("S[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1342         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1343                 return die_("copying object");
1344         if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1345                 return die_("setting APPLICATION data");
1346         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1347                 return die_("copying object");
1348         if(!FLAC__metadata_iterator_set_block(iterator, app))
1349                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1350
1351         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1352                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1353         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1354                 return false;
1355         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1356                 return false;
1357
1358         printf("S[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1359         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1360                 return die_("copying object");
1361         if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1362                 return die_("setting APPLICATION data");
1363         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1364                 return die_("copying object");
1365         our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1366         if(!FLAC__metadata_iterator_set_block(iterator, app))
1367                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1368
1369         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1370                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1371         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1372                 return false;
1373         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1374                 return false;
1375
1376         printf("S[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1377         if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1378                 return die_("copying object");
1379         if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1380                 return die_("setting APPLICATION data");
1381         if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1382                 return die_("copying object");
1383         delete_from_our_metadata_(our_current_position+1);
1384         if(!FLAC__metadata_iterator_set_block(iterator, app))
1385                 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1386
1387         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1388                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1389         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1390                 return false;
1391         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1392                 return false;
1393
1394         printf("S[A]\tprev\n");
1395         if(!FLAC__metadata_iterator_prev(iterator))
1396                 return die_("iterator ended early\n");
1397         our_current_position--;
1398
1399         printf("[S]A\tinsert PADDING before STREAMINFO (should fail)\n");
1400         if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1401                 return die_("creating PADDING block");
1402         padding->length = 30;
1403         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1404                 printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1405         else
1406                 return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1407
1408         printf("[S]A\tinsert PADDING after\n");
1409         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1410                 return die_("copying metadata");
1411         if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1412                 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1413
1414         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1415                 return false;
1416
1417         printf("S[P]A\tinsert PADDING before\n");
1418         if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1419                 return die_("creating PADDING block");
1420         padding->length = 17;
1421         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1422                 return die_("copying metadata");
1423         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1424                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1425
1426         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1427                 return false;
1428
1429         printf("S[P]PA\tinsert PADDING before\n");
1430         if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
1431                 return die_("creating PADDING block");
1432         padding->length = 0;
1433         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1434                 return die_("copying metadata");
1435         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1436                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1437
1438         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1439                 return false;
1440
1441         printf("S[P]PPA\tnext\n");
1442         if(!FLAC__metadata_iterator_next(iterator))
1443                 return die_("iterator ended early\n");
1444         our_current_position++;
1445
1446         printf("SP[P]PA\tnext\n");
1447         if(!FLAC__metadata_iterator_next(iterator))
1448                 return die_("iterator ended early\n");
1449         our_current_position++;
1450
1451         printf("SPP[P]A\tnext\n");
1452         if(!FLAC__metadata_iterator_next(iterator))
1453                 return die_("iterator ended early\n");
1454         our_current_position++;
1455
1456         printf("SPPP[A]\tinsert PADDING after\n");
1457         if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[1])))
1458                 return die_("creating PADDING block");
1459         padding->length = 57;
1460         if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1461                 return die_("copying metadata");
1462         if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1463                 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1464
1465         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1466                 return false;
1467
1468         printf("SPPPA[P]\tinsert PADDING before\n");
1469         if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[1])))
1470                 return die_("creating PADDING block");
1471         padding->length = 99;
1472         if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1473                 return die_("copying metadata");
1474         if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1475                 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1476
1477         if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1478                 return false;
1479
1480         printf("delete iterator\n");
1481         FLAC__metadata_iterator_delete(iterator);
1482         our_current_position = 0;
1483
1484         printf("SPPPAPP\tmerge padding\n");
1485         FLAC__metadata_chain_merge_padding(chain);
1486         our_metadata_.blocks[1]->length += (4 + our_metadata_.blocks[2]->length);
1487         our_metadata_.blocks[1]->length += (4 + our_metadata_.blocks[3]->length);
1488         our_metadata_.blocks[5]->length += (4 + our_metadata_.blocks[6]->length);
1489         delete_from_our_metadata_(6);
1490         delete_from_our_metadata_(3);
1491         delete_from_our_metadata_(2);
1492
1493         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1494                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1495         if(!compare_chain_(chain, 0, 0))
1496                 return false;
1497         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1498                 return false;
1499
1500         printf("SPAP\tsort padding\n");
1501         FLAC__metadata_chain_sort_padding(chain);
1502         our_metadata_.blocks[3]->length += (4 + our_metadata_.blocks[1]->length);
1503         delete_from_our_metadata_(1);
1504
1505         if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
1506                 return die_c_("during FLAC__metadata_chain_write(chain, true, true)", FLAC__metadata_chain_status(chain));
1507         if(!compare_chain_(chain, 0, 0))
1508                 return false;
1509         if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
1510                 return false;
1511
1512         printf("delete chain\n");
1513
1514         FLAC__metadata_chain_delete(chain);
1515
1516         if(!remove_file_(flacfile_))
1517                 return false;
1518
1519         return true;
1520 }
1521
1522 int test_metadata_file_manipulation(const char *progname)
1523 {
1524         printf("\n+++ unit test: metadata manipulation\n\n");
1525
1526         our_metadata_.num_blocks = 0;
1527
1528         if(!test_level_0_(progname))
1529                 return 1;
1530
1531         if(!test_level_1_(progname))
1532                 return 1;
1533
1534         if(!test_level_2_(progname))
1535                 return 1;
1536
1537         return 0;
1538 }