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