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