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