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