1 /* test_libFLAC - Unit tester for libFLAC
2 * Copyright (C) 2002-2009 Josh Coalson
3 * Copyright (C) 2011-2023 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) && !defined(_WIN32)
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 if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
911 return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
912
913 printf("[S]VP\tnext\n");
914 if(!FLAC__metadata_simple_iterator_next(iterator))
915 return die_("iterator ended early\n");
916 our_current_position++;
917
918 printf("S[V]P\tnext\n");
919 if(!FLAC__metadata_simple_iterator_next(iterator))
920 return die_("iterator ended early\n");
921 our_current_position++;
922
923 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
924 padding->length = 25;
925 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
926 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
927 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
928 return false;
929
930 printf("SVP[P]\tprev\n");
931 if(!FLAC__metadata_simple_iterator_prev(iterator))
932 return die_("iterator ended early\n");
933 our_current_position--;
934
935 printf("SV[P]P\tprev\n");
936 if(!FLAC__metadata_simple_iterator_prev(iterator))
937 return die_("iterator ended early\n");
938 our_current_position--;
939
940 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
941 padding->length = 30;
942 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
943 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
944 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
945 return false;
946
947 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
948 return false;
949
950 printf("SV[P]PP\tprev\n");
951 if(!FLAC__metadata_simple_iterator_prev(iterator))
952 return die_("iterator ended early\n");
953 our_current_position--;
954
955 printf("S[V]PPP\tprev\n");
956 if(!FLAC__metadata_simple_iterator_prev(iterator))
957 return die_("iterator ended early\n");
958 our_current_position--;
959
960 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
961 if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
962 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
963
964 if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
965 return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
966
967 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
968 return false;
969
970 printf("[S]VPPP\tnext\n");
971 if(!FLAC__metadata_simple_iterator_next(iterator))
972 return die_("iterator ended early\n");
973 our_current_position++;
974
975 printf("S[V]PPP\tnext\n");
976 if(!FLAC__metadata_simple_iterator_next(iterator))
977 return die_("iterator ended early\n");
978 our_current_position++;
979
980 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
981 if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
982 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
983 our_current_position--;
984
985 printf("S[V]PPP\tnext\n");
986 if(!FLAC__metadata_simple_iterator_next(iterator))
987 return die_("iterator ended early\n");
988 our_current_position++;
989
990 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
991 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
992 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
993 delete_from_our_metadata_(our_current_position--);
994
995 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
996 return false;
997
998 printf("S[V]PP\tnext\n");
999 if(!FLAC__metadata_simple_iterator_next(iterator))
1000 return die_("iterator ended early\n");
1001 our_current_position++;
1002
1003 printf("SV[P]P\tnext\n");
1004 if(!FLAC__metadata_simple_iterator_next(iterator))
1005 return die_("iterator ended early\n");
1006 our_current_position++;
1007
1008 printf("SVP[P]\tdelete (last block), replace with padding\n");
1009 if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
1010 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1011 our_current_position--;
1012
1013 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1014 return false;
1015
1016 printf("SV[P]P\tnext\n");
1017 if(!FLAC__metadata_simple_iterator_next(iterator))
1018 return die_("iterator ended early\n");
1019 our_current_position++;
1020
1021 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1022 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1023 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1024 delete_from_our_metadata_(our_current_position--);
1025
1026 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1027 return false;
1028
1029 printf("SV[P]\tprev\n");
1030 if(!FLAC__metadata_simple_iterator_prev(iterator))
1031 return die_("iterator ended early\n");
1032 our_current_position--;
1033
1034 printf("S[V]P\tprev\n");
1035 if(!FLAC__metadata_simple_iterator_prev(iterator))
1036 return die_("iterator ended early\n");
1037 our_current_position--;
1038
1039 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1040 FLAC__ASSERT(our_current_position == 0);
1041 block = FLAC__metadata_simple_iterator_get_block(iterator);
1042 block->data.stream_info.sample_rate = 32000;
1043 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1044 return die_("copying object");
1045 if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
1046 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
1047 FLAC__metadata_object_delete(block);
1048
1049 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1050 return false;
1051
1052 printf("[S]VP\tnext\n");
1053 if(!FLAC__metadata_simple_iterator_next(iterator))
1054 return die_("iterator ended early\n");
1055 our_current_position++;
1056
1057 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1058 app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
1059 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1060 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1061 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1062 return false;
1063 our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1064
1065 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1066 return false;
1067
1068 printf("SV[A]P\tnext\n");
1069 if(!FLAC__metadata_simple_iterator_next(iterator))
1070 return die_("iterator ended early\n");
1071 our_current_position++;
1072
1073 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1074 app->data.application.id[0] = 'f'; /* twiddle the id */
1075 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1076 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1077 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1078 return false;
1079 our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1080
1081 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1082 return false;
1083
1084 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1085 app->data.application.id[0] = 'g'; /* twiddle the id */
1086 if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1087 return die_("setting APPLICATION data");
1088 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1089 return die_("copying object");
1090 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1091 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1092
1093 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1094 return false;
1095
1096 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1097 app->data.application.id[0] = 'h'; /* twiddle the id */
1098 if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
1099 return die_("setting APPLICATION data");
1100 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1101 return die_("copying object");
1102 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1103 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1104
1105 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1106 return false;
1107
1108 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1109 app->data.application.id[0] = 'i'; /* twiddle the id */
1110 if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1111 return die_("setting APPLICATION data");
1112 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1113 return die_("copying object");
1114 our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
1115 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1116 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1117
1118 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1119 return false;
1120
1121 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1122 app->data.application.id[0] = 'j'; /* twiddle the id */
1123 if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
1124 return die_("setting APPLICATION data");
1125 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1126 return die_("copying object");
1127 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1128 return die_("copying object");
1129 our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
1130 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1131 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1132
1133 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1134 return false;
1135
1136 printf("SVA[A]PP\tnext\n");
1137 if(!FLAC__metadata_simple_iterator_next(iterator))
1138 return die_("iterator ended early\n");
1139 our_current_position++;
1140
1141 printf("SVAA[P]P\tnext\n");
1142 if(!FLAC__metadata_simple_iterator_next(iterator))
1143 return die_("iterator ended early\n");
1144 our_current_position++;
1145
1146 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1147 padding->length = 5;
1148 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1149 return die_("copying object");
1150 if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1151 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1152
1153 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1154 return false;
1155
1156 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1157 app->data.application.id[0] = 'k'; /* twiddle the id */
1158 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1159 return die_("copying object");
1160 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1161 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1162
1163 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1164 return false;
1165
1166 printf("SVAAP[A]\tset PADDING (equal)\n");
1167 padding->length = 27;
1168 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1169 return die_("copying object");
1170 if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1171 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1172
1173 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1174 return false;
1175
1176 printf("SVAAP[P]\tprev\n");
1177 if(!FLAC__metadata_simple_iterator_prev(iterator))
1178 return die_("iterator ended early\n");
1179 our_current_position--;
1180
1181 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1182 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1183 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1184 delete_from_our_metadata_(our_current_position--);
1185
1186 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1187 return false;
1188
1189 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1190 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1191 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1192 delete_from_our_metadata_(our_current_position--);
1193
1194 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1195 return false;
1196
1197 printf("SV[A]P\tnext\n");
1198 if(!FLAC__metadata_simple_iterator_next(iterator))
1199 return die_("iterator ended early\n");
1200 our_current_position++;
1201
1202 printf("SVA[P]\tinsert PADDING after\n");
1203 padding->length = 5;
1204 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1205 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1206 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1207 return false;
1208
1209 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1210 return false;
1211
1212 printf("SVAP[P]\tprev\n");
1213 if(!FLAC__metadata_simple_iterator_prev(iterator))
1214 return die_("iterator ended early\n");
1215 our_current_position--;
1216
1217 printf("SVA[P]P\tprev\n");
1218 if(!FLAC__metadata_simple_iterator_prev(iterator))
1219 return die_("iterator ended early\n");
1220 our_current_position--;
1221
1222 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1223 if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
1224 return die_("setting APPLICATION data");
1225 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1226 return die_("copying object");
1227 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1228 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1229
1230 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1231 return false;
1232
1233 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1234 if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
1235 return die_("setting APPLICATION data");
1236 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1237 return die_("copying object");
1238 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1239 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1240
1241 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1242 return false;
1243
1244 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1245 if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
1246 return die_("setting APPLICATION data");
1247 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1248 return die_("copying object");
1249 our_metadata_.blocks[our_current_position+1]->length = 0;
1250 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1251 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1252
1253 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1254 return false;
1255
1256 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1257 if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
1258 return die_("setting APPLICATION data");
1259 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1260 return die_("copying object");
1261 delete_from_our_metadata_(our_current_position+1);
1262 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1263 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1264
1265 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1266 return false;
1267
1268 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1269 if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1270 return die_("setting APPLICATION data");
1271 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1272 return die_("copying object");
1273 delete_from_our_metadata_(our_current_position+1);
1274 our_metadata_.blocks[our_current_position]->is_last = true;
1275 if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1276 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1277
1278 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1279 return false;
1280
1281 printf("SV[A]\tset PADDING (equal size)\n");
1282 padding->length = app->length;
1283 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1284 return die_("copying object");
1285 if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
1286 return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
1287
1288 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1289 return false;
1290
1291 printf("SV[P]\tinsert PADDING after\n");
1292 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1293 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1294 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1295 return false;
1296
1297 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1298 return false;
1299
1300 printf("SVP[P]\tinsert PADDING after\n");
1301 padding->length = 5;
1302 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1303 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1304 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1305 return false;
1306
1307 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1308 return false;
1309
1310 printf("SVPP[P]\tprev\n");
1311 if(!FLAC__metadata_simple_iterator_prev(iterator))
1312 return die_("iterator ended early\n");
1313 our_current_position--;
1314
1315 printf("SVP[P]P\tprev\n");
1316 if(!FLAC__metadata_simple_iterator_prev(iterator))
1317 return die_("iterator ended early\n");
1318 our_current_position--;
1319
1320 printf("SV[P]PP\tprev\n");
1321 if(!FLAC__metadata_simple_iterator_prev(iterator))
1322 return die_("iterator ended early\n");
1323 our_current_position--;
1324
1325 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1326 if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1327 return die_("setting APPLICATION data");
1328 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1329 return die_("copying object");
1330 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1331 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1332
1333 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1334 return false;
1335
1336 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1337 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1338 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1339 delete_from_our_metadata_(our_current_position--);
1340
1341 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1342 return false;
1343
1344 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1345 if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1346 return die_("setting APPLICATION data");
1347 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1348 return die_("copying object");
1349 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1350 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1351
1352 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1353 return false;
1354
1355 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1356 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1357 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1358 delete_from_our_metadata_(our_current_position--);
1359
1360 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1361 return false;
1362
1363 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1364 if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1365 return die_("setting APPLICATION data");
1366 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1367 return die_("copying object");
1368 delete_from_our_metadata_(our_current_position+1);
1369 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1370 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1371
1372 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1373 return false;
1374
1375 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1376 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1377 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1378 delete_from_our_metadata_(our_current_position--);
1379
1380 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1381 return false;
1382
1383 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1384 if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1385 return die_("setting APPLICATION data");
1386 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1387 return die_("copying object");
1388 our_metadata_.blocks[our_current_position+1]->length = 0;
1389 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1390 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1391
1392 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1393 return false;
1394
1395 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1396 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1397 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1398 delete_from_our_metadata_(our_current_position--);
1399
1400 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1401 return false;
1402
1403 printf("S[V]PP\tnext\n");
1404 if(!FLAC__metadata_simple_iterator_next(iterator))
1405 return die_("iterator ended early\n");
1406 our_current_position++;
1407
1408 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1409 if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1410 return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1411 delete_from_our_metadata_(our_current_position--);
1412
1413 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1414 return false;
1415
1416 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1417 if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1418 return die_("setting APPLICATION data");
1419 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1420 return die_("copying object");
1421 delete_from_our_metadata_(our_current_position+1);
1422 if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1423 return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1424
1425 if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1426 return false;
1427
1428 printf("delete simple iterator\n");
1429
1430 FLAC__metadata_simple_iterator_delete(iterator);
1431
1432 FLAC__metadata_object_delete(app);
1433 FLAC__metadata_object_delete(padding);
1434
1435 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1436 return false;
1437
1438 return true;
1439 }
1440
test_level_2_(FLAC__bool filename_based,FLAC__bool is_ogg)1441 static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
1442 {
1443 FLAC__Metadata_Iterator *iterator;
1444 FLAC__Metadata_Chain *chain;
1445 FLAC__StreamMetadata *block, *app, *padding;
1446 FLAC__byte data[2000];
1447 uint32_t our_current_position;
1448
1449 /* initialize 'data' to avoid Valgrind errors */
1450 memset(data, 0, sizeof(data));
1451
1452 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1453
1454 printf("generate read-only file\n");
1455
1456 if(!generate_file_(/*include_extras=*/false, is_ogg))
1457 return false;
1458
1459 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1460 return false;
1461
1462 printf("create chain\n");
1463
1464 if(0 == (chain = FLAC__metadata_chain_new()))
1465 return die_("allocating chain");
1466
1467 printf("read chain\n");
1468
1469 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1470 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1471
1472 printf("[S]VP\ttest initial metadata\n");
1473
1474 if(!compare_chain_(chain, 0, 0))
1475 return false;
1476 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1477 return false;
1478
1479 if(is_ogg)
1480 goto end;
1481
1482 printf("switch file to read-write\n");
1483
1484 if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1485 return false;
1486
1487 printf("create iterator\n");
1488 if(0 == (iterator = FLAC__metadata_iterator_new()))
1489 return die_("allocating memory for iterator");
1490
1491 our_current_position = 0;
1492
1493 FLAC__metadata_iterator_init(iterator, chain);
1494
1495 if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1496 return die_("getting block from iterator");
1497
1498 FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1499
1500 printf("[S]VP\tmodify STREAMINFO, write\n");
1501
1502 block->data.stream_info.sample_rate = 32000;
1503 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1504 return die_("copying object");
1505
1506 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1507 return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1508 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1509 return false;
1510 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1511 return false;
1512
1513 printf("[S]VP\tnext\n");
1514 if(!FLAC__metadata_iterator_next(iterator))
1515 return die_("iterator ended early\n");
1516 our_current_position++;
1517
1518 printf("S[V]P\tnext\n");
1519 if(!FLAC__metadata_iterator_next(iterator))
1520 return die_("iterator ended early\n");
1521 our_current_position++;
1522
1523 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1524 if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1525 return die_("getting block from iterator");
1526 if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1527 return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1528 memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1529 if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1530 return die_("setting APPLICATION data");
1531 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1532 return die_("copying object");
1533 if(!FLAC__metadata_iterator_set_block(iterator, app))
1534 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1535
1536 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1537 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1538 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1539 return false;
1540 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1541 return false;
1542
1543 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1544 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1545 return die_("copying object");
1546 if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1547 return die_("setting APPLICATION data");
1548 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1549 return die_("copying object");
1550 if(!FLAC__metadata_iterator_set_block(iterator, app))
1551 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1552
1553 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1554 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1555 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1556 return false;
1557 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1558 return false;
1559
1560 printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1561 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1562 return die_("copying object");
1563 if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1564 return die_("setting APPLICATION data");
1565 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1566 return die_("copying object");
1567 if(!FLAC__metadata_iterator_set_block(iterator, app))
1568 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1569
1570 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1571 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1572 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1573 return false;
1574 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1575 return false;
1576
1577 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1578 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1579 return die_("copying object");
1580 if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1581 return die_("setting APPLICATION data");
1582 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1583 return die_("copying object");
1584 if(!FLAC__metadata_iterator_set_block(iterator, app))
1585 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1586
1587 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1588 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1589 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1590 return false;
1591 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1592 return false;
1593
1594 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1595 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1596 return die_("copying object");
1597 if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1598 return die_("setting APPLICATION data");
1599 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1600 return die_("copying object");
1601 if(!FLAC__metadata_iterator_set_block(iterator, app))
1602 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1603
1604 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1605 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1606 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1607 return false;
1608 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1609 return false;
1610
1611 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1612 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1613 return die_("creating PADDING block");
1614 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1615 return die_("copying object");
1616 if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1617 return die_("setting APPLICATION data");
1618 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1619 return die_("copying object");
1620 padding->length = 0;
1621 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1622 return die_("internal error");
1623 if(!FLAC__metadata_iterator_set_block(iterator, app))
1624 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1625
1626 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1627 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1628 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1629 return false;
1630 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1631 return false;
1632
1633 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1634 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1635 return die_("copying object");
1636 if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1637 return die_("setting APPLICATION data");
1638 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1639 return die_("copying object");
1640 our_metadata_.blocks[our_current_position+1]->length = 13;
1641 if(!FLAC__metadata_iterator_set_block(iterator, app))
1642 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1643
1644 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1645 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1646 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1647 return false;
1648 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1649 return false;
1650
1651 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1652 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1653 return die_("copying object");
1654 if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1655 return die_("setting APPLICATION data");
1656 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1657 return die_("copying object");
1658 if(!FLAC__metadata_iterator_set_block(iterator, app))
1659 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1660
1661 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1662 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1663 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1664 return false;
1665 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1666 return false;
1667
1668 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1669 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1670 return die_("copying object");
1671 if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1672 return die_("setting APPLICATION data");
1673 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1674 return die_("copying object");
1675 our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1676 if(!FLAC__metadata_iterator_set_block(iterator, app))
1677 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1678
1679 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1680 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1681 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1682 return false;
1683 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1684 return false;
1685
1686 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1687 if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1688 return die_("copying object");
1689 if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1690 return die_("setting APPLICATION data");
1691 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1692 return die_("copying object");
1693 delete_from_our_metadata_(our_current_position+1);
1694 if(!FLAC__metadata_iterator_set_block(iterator, app))
1695 return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1696
1697 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1698 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1699 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1700 return false;
1701 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1702 return false;
1703
1704 printf("SV[A]\tprev\n");
1705 if(!FLAC__metadata_iterator_prev(iterator))
1706 return die_("iterator ended early\n");
1707 our_current_position--;
1708
1709 printf("S[V]A\tprev\n");
1710 if(!FLAC__metadata_iterator_prev(iterator))
1711 return die_("iterator ended early\n");
1712 our_current_position--;
1713
1714 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1715 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1716 return die_("creating PADDING block");
1717 padding->length = 30;
1718 if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1719 printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1720 else
1721 return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1722
1723 printf("[S]VP\tnext\n");
1724 if(!FLAC__metadata_iterator_next(iterator))
1725 return die_("iterator ended early\n");
1726 our_current_position++;
1727
1728 printf("S[V]A\tinsert PADDING after\n");
1729 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1730 return die_("copying metadata");
1731 if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1732 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1733
1734 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1735 return false;
1736
1737 printf("SV[P]A\tinsert PADDING before\n");
1738 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1739 return die_("creating PADDING block");
1740 padding->length = 17;
1741 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1742 return die_("copying metadata");
1743 if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1744 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1745
1746 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1747 return false;
1748
1749 printf("SV[P]PA\tinsert PADDING before\n");
1750 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1751 return die_("creating PADDING block");
1752 padding->length = 0;
1753 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1754 return die_("copying metadata");
1755 if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1756 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1757
1758 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1759 return false;
1760
1761 printf("SV[P]PPA\tnext\n");
1762 if(!FLAC__metadata_iterator_next(iterator))
1763 return die_("iterator ended early\n");
1764 our_current_position++;
1765
1766 printf("SVP[P]PA\tnext\n");
1767 if(!FLAC__metadata_iterator_next(iterator))
1768 return die_("iterator ended early\n");
1769 our_current_position++;
1770
1771 printf("SVPP[P]A\tnext\n");
1772 if(!FLAC__metadata_iterator_next(iterator))
1773 return die_("iterator ended early\n");
1774 our_current_position++;
1775
1776 printf("SVPPP[A]\tinsert PADDING after\n");
1777 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1778 return die_("creating PADDING block");
1779 padding->length = 57;
1780 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1781 return die_("copying metadata");
1782 if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1783 return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1784
1785 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1786 return false;
1787
1788 printf("SVPPPA[P]\tinsert PADDING before\n");
1789 if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1790 return die_("creating PADDING block");
1791 padding->length = 99;
1792 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1793 return die_("copying metadata");
1794 if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1795 return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1796
1797 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1798 return false;
1799
1800 printf("delete iterator\n");
1801 FLAC__metadata_iterator_delete(iterator);
1802 our_current_position = 0;
1803
1804 printf("SVPPPAPP\tmerge padding\n");
1805 FLAC__metadata_chain_merge_padding(chain);
1806 our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1807 our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
1808 our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
1809 delete_from_our_metadata_(7);
1810 delete_from_our_metadata_(4);
1811 delete_from_our_metadata_(3);
1812
1813 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1814 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1815 if(!compare_chain_(chain, 0, 0))
1816 return false;
1817 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1818 return false;
1819
1820 printf("SVPAP\tsort padding\n");
1821 FLAC__metadata_chain_sort_padding(chain);
1822 our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1823 delete_from_our_metadata_(2);
1824
1825 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1826 return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1827 if(!compare_chain_(chain, 0, 0))
1828 return false;
1829 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1830 return false;
1831
1832 printf("create iterator\n");
1833 if(0 == (iterator = FLAC__metadata_iterator_new()))
1834 return die_("allocating memory for iterator");
1835
1836 our_current_position = 0;
1837
1838 FLAC__metadata_iterator_init(iterator, chain);
1839
1840 printf("[S]VAP\tnext\n");
1841 if(!FLAC__metadata_iterator_next(iterator))
1842 return die_("iterator ended early\n");
1843 our_current_position++;
1844
1845 printf("S[V]AP\tnext\n");
1846 if(!FLAC__metadata_iterator_next(iterator))
1847 return die_("iterator ended early\n");
1848 our_current_position++;
1849
1850 printf("SV[A]P\tdelete middle block, replace with padding\n");
1851 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1852 return die_("creating PADDING block");
1853 padding->length = 71;
1854 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1855 return die_("copying object");
1856 if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1857 return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1858
1859 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1860 return false;
1861
1862 printf("S[V]PP\tnext\n");
1863 if(!FLAC__metadata_iterator_next(iterator))
1864 return die_("iterator ended early\n");
1865 our_current_position++;
1866
1867 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1868 delete_from_our_metadata_(our_current_position--);
1869 if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1870 return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1871
1872 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1873 return false;
1874
1875 printf("S[V]P\tnext\n");
1876 if(!FLAC__metadata_iterator_next(iterator))
1877 return die_("iterator ended early\n");
1878 our_current_position++;
1879
1880 printf("SV[P]\tdelete last block, replace with padding\n");
1881 if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1882 return die_("creating PADDING block");
1883 padding->length = 219;
1884 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1885 return die_("copying object");
1886 if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1887 return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1888
1889 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1890 return false;
1891
1892 printf("S[V]P\tnext\n");
1893 if(!FLAC__metadata_iterator_next(iterator))
1894 return die_("iterator ended early\n");
1895 our_current_position++;
1896
1897 printf("SV[P]\tdelete last block, don't replace with padding\n");
1898 delete_from_our_metadata_(our_current_position--);
1899 if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1900 return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1901
1902 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1903 return false;
1904
1905 printf("S[V]\tprev\n");
1906 if(!FLAC__metadata_iterator_prev(iterator))
1907 return die_("iterator ended early\n");
1908 our_current_position--;
1909
1910 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1911 if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1912 return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
1913
1914 if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1915 return false;
1916
1917 printf("delete iterator\n");
1918 FLAC__metadata_iterator_delete(iterator);
1919 our_current_position = 0;
1920
1921 printf("SV\tmerge padding\n");
1922 FLAC__metadata_chain_merge_padding(chain);
1923
1924 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1925 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1926 if(!compare_chain_(chain, 0, 0))
1927 return false;
1928 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1929 return false;
1930
1931 printf("SV\tsort padding\n");
1932 FLAC__metadata_chain_sort_padding(chain);
1933
1934 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1935 return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1936 if(!compare_chain_(chain, 0, 0))
1937 return false;
1938 if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1939 return false;
1940
1941 end:
1942 printf("delete chain\n");
1943
1944 FLAC__metadata_chain_delete(chain);
1945
1946 if(!remove_file_(flacfilename(is_ogg)))
1947 return false;
1948
1949 return true;
1950 }
1951
test_level_2_misc_(FLAC__bool is_ogg)1952 static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
1953 {
1954 FLAC__Metadata_Iterator *iterator;
1955 FLAC__Metadata_Chain *chain;
1956 FLAC__IOCallbacks callbacks;
1957
1958 memset(&callbacks, 0, sizeof(callbacks));
1959 callbacks.read = (FLAC__IOCallback_Read)fread;
1960 #ifdef FLAC__VALGRIND_TESTING
1961 callbacks.write = chain_write_cb_;
1962 #else
1963 callbacks.write = (FLAC__IOCallback_Write)fwrite;
1964 #endif
1965 callbacks.seek = chain_seek_cb_;
1966 callbacks.tell = chain_tell_cb_;
1967 callbacks.eof = chain_eof_cb_;
1968
1969 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1970
1971 printf("generate file\n");
1972
1973 if(!generate_file_(/*include_extras=*/false, is_ogg))
1974 return false;
1975
1976 printf("create chain\n");
1977
1978 if(0 == (chain = FLAC__metadata_chain_new()))
1979 return die_("allocating chain");
1980
1981 printf("read chain (filename-based)\n");
1982
1983 if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1984 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1985
1986 printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
1987 {
1988 if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
1989 return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1990 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1991 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1992 printf(" OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1993 }
1994
1995 printf("read chain (filename-based)\n");
1996
1997 if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1998 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1999
2000 printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2001 {
2002 if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2003 return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2004 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2005 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2006 printf(" OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2007 }
2008
2009 printf("read chain (callback-based)\n");
2010 {
2011 FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2012 if(0 == file)
2013 return die_("opening file");
2014 if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2015 fclose(file);
2016 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2017 }
2018 fclose(file);
2019 }
2020
2021 printf("write chain with wrong method FLAC__metadata_chain_write()\n");
2022 {
2023 if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
2024 return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2025 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2026 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2027 printf(" OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2028 }
2029
2030 printf("read chain (callback-based)\n");
2031 {
2032 FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2033 if(0 == file)
2034 return die_("opening file");
2035 if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2036 fclose(file);
2037 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2038 }
2039 fclose(file);
2040 }
2041
2042 printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2043
2044 if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2045 printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
2046 else
2047 return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
2048
2049 printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2050 {
2051 if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2052 return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2053 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2054 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2055 printf(" OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2056 }
2057
2058 printf("read chain (callback-based)\n");
2059 {
2060 FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2061 if(0 == file)
2062 return die_("opening file");
2063 if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2064 fclose(file);
2065 return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2066 }
2067 fclose(file);
2068 }
2069
2070 printf("create iterator\n");
2071 if(0 == (iterator = FLAC__metadata_iterator_new()))
2072 return die_("allocating memory for iterator");
2073
2074 FLAC__metadata_iterator_init(iterator, chain);
2075
2076 printf("[S]VP\tnext\n");
2077 if(!FLAC__metadata_iterator_next(iterator))
2078 return die_("iterator ended early\n");
2079
2080 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2081 if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
2082 return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
2083
2084 printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2085
2086 if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2087 printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
2088 else
2089 return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
2090
2091 printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
2092 {
2093 if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
2094 return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2095 if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2096 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2097 printf(" OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2098 }
2099
2100 printf("delete iterator\n");
2101
2102 FLAC__metadata_iterator_delete(iterator);
2103
2104 printf("delete chain\n");
2105
2106 FLAC__metadata_chain_delete(chain);
2107
2108 if(!remove_file_(flacfilename(is_ogg)))
2109 return false;
2110
2111 return true;
2112 }
2113
test_metadata_file_manipulation(void)2114 FLAC__bool test_metadata_file_manipulation(void)
2115 {
2116 printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
2117
2118 our_metadata_.num_blocks = 0;
2119
2120 if(!test_level_0_())
2121 return false;
2122
2123 if(!test_level_1_())
2124 return false;
2125
2126 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2127 return false;
2128 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2129 return false;
2130 if(!test_level_2_misc_(/*is_ogg=*/false))
2131 return false;
2132
2133 if(FLAC_API_SUPPORTS_OGG_FLAC) {
2134 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2135 return false;
2136 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2137 return false;
2138 #if 0
2139 /* when ogg flac write is supported, will have to add this: */
2140 if(!test_level_2_misc_(/*is_ogg=*/true))
2141 return false;
2142 #endif
2143 }
2144
2145 return true;
2146 }
2147