Fix a couple of Windows 2Gig file size issues.
[flac.git] / src / test_libFLAC++ / metadata_manip.cpp
blobff024162c6bd75d0a9b3ab296984acf4664f877d
1 /* test_libFLAC++ - Unit tester for libFLAC++
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Josh Coalson
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.
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.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h> /* for malloc() */
25 #include <string.h> /* for memcpy()/memset() */
26 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
27 #ifdef _MSC_VER
28 #include <sys/utime.h>
29 #else
30 #include <utime.h> /* for utime() */
31 #endif
32 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
33 #include <unistd.h> /* for chown(), unlink() */
34 #endif
35 #include <sys/stat.h> /* for stat(), maybe chmod() */
36 #include "FLAC/assert.h"
37 #include "FLAC++/decoder.h"
38 #include "FLAC++/metadata.h"
39 #include "share/grabbag.h"
40 #include "share/compat.h"
41 #include "share/macros.h"
42 extern "C" {
43 #include "test_libs_common/file_utils_flac.h"
46 /******************************************************************************
47 The general strategy of these tests (for interface levels 1 and 2) is
48 to create a dummy FLAC file with a known set of initial metadata
49 blocks, then keep a mirror locally of what we expect the metadata to be
50 after each operation. Then testing becomes a simple matter of running
51 a FLAC::Decoder::File over the dummy file after each operation, comparing
52 the decoded metadata to what's in our local copy. If there are any
53 differences in the metadata, or the actual audio data is corrupted, we
54 will catch it while decoding.
55 ******************************************************************************/
57 class OurFileDecoder: public FLAC::Decoder::File {
58 public:
59 inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
61 bool ignore_metadata_;
62 bool error_occurred_;
63 protected:
64 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
65 void metadata_callback(const ::FLAC__StreamMetadata *metadata);
66 void error_callback(::FLAC__StreamDecoderErrorStatus status);
69 struct OurMetadata {
70 FLAC::Metadata::Prototype *blocks[64];
71 unsigned num_blocks;
74 /* our copy of the metadata in flacfilename() */
75 static OurMetadata our_metadata_;
77 /* the current block number that corresponds to the position of the iterator we are testing */
78 static unsigned mc_our_block_number_ = 0;
80 static const char *flacfilename(bool is_ogg)
82 return is_ogg? "metadata.oga" : "metadata.flac";
85 static bool die_(const char *msg)
87 printf("ERROR: %s\n", msg);
88 return false;
91 static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
93 printf("ERROR: %s\n", msg);
94 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
95 return false;
98 static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
100 const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
101 printf("ERROR: %s\n", msg);
102 printf(" status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
103 return false;
106 static void *malloc_or_die_(size_t size)
108 void *x = malloc(size);
109 if(0 == x) {
110 fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
111 exit(1);
113 return x;
116 static char *strdup_or_die_(const char *s)
118 char *x = strdup(s);
119 if(0 == x) {
120 fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
121 exit(1);
123 return x;
126 /* functions for working with our metadata copy */
128 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
130 unsigned i;
131 FLAC::Metadata::Prototype *obj = block;
132 FLAC__ASSERT(position < our_metadata_.num_blocks);
133 if(copy) {
134 if(0 == (obj = FLAC::Metadata::clone(block)))
135 return die_("during FLAC::Metadata::clone()");
137 delete our_metadata_.blocks[position];
138 our_metadata_.blocks[position] = obj;
140 /* set the is_last flags */
141 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
142 our_metadata_.blocks[i]->set_is_last(false);
143 our_metadata_.blocks[i]->set_is_last(true);
145 return true;
148 static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
150 unsigned i;
151 FLAC::Metadata::Prototype *obj = block;
152 if(copy) {
153 if(0 == (obj = FLAC::Metadata::clone(block)))
154 return die_("during FLAC::Metadata::clone()");
156 if(position > our_metadata_.num_blocks) {
157 position = our_metadata_.num_blocks;
159 else {
160 for(i = our_metadata_.num_blocks; i > position; i--)
161 our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
163 our_metadata_.blocks[position] = obj;
164 our_metadata_.num_blocks++;
166 /* set the is_last flags */
167 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
168 our_metadata_.blocks[i]->set_is_last(false);
169 our_metadata_.blocks[i]->set_is_last(true);
171 return true;
174 static void delete_from_our_metadata_(unsigned position)
176 unsigned i;
177 FLAC__ASSERT(position < our_metadata_.num_blocks);
178 delete our_metadata_.blocks[position];
179 for(i = position; i < our_metadata_.num_blocks - 1; i++)
180 our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
181 our_metadata_.num_blocks--;
183 /* set the is_last flags */
184 if(our_metadata_.num_blocks > 0) {
185 for(i = 0; i < our_metadata_.num_blocks - 1; i++)
186 our_metadata_.blocks[i]->set_is_last(false);
187 our_metadata_.blocks[i]->set_is_last(true);
191 void add_to_padding_length_(unsigned index, int delta)
193 FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
194 FLAC__ASSERT(0 != padding);
195 padding->set_length((unsigned)((int)padding->get_length() + delta));
199 * This wad of functions supports filename- and callback-based chain reading/writing.
200 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
202 bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
204 static const char *tempfile_suffix = ".metadata_edit";
206 if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
207 return false;
208 strcpy(*tempfilename, filename);
209 strcat(*tempfilename, tempfile_suffix);
211 if(0 == (*tempfile = fopen(*tempfilename, "wb")))
212 return false;
214 return true;
217 void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
219 if(0 != *tempfile) {
220 (void)fclose(*tempfile);
221 *tempfile = 0;
224 if(0 != *tempfilename) {
225 (void)unlink(*tempfilename);
226 free(*tempfilename);
227 *tempfilename = 0;
231 bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
233 FLAC__ASSERT(0 != filename);
234 FLAC__ASSERT(0 != tempfile);
235 FLAC__ASSERT(0 != tempfilename);
236 FLAC__ASSERT(0 != *tempfilename);
238 if(0 != *tempfile) {
239 (void)fclose(*tempfile);
240 *tempfile = 0;
243 #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
244 /* on some flavors of windows, rename() will fail if the destination already exists */
245 if(unlink(filename) < 0) {
246 cleanup_tempfile_(tempfile, tempfilename);
247 return false;
249 #endif
251 if(0 != rename(*tempfilename, filename)) {
252 cleanup_tempfile_(tempfile, tempfilename);
253 return false;
256 cleanup_tempfile_(tempfile, tempfilename);
258 return true;
261 bool get_file_stats_(const char *filename, struct stat *stats)
263 FLAC__ASSERT(0 != filename);
264 FLAC__ASSERT(0 != stats);
265 return (0 == stat(filename, stats));
268 void set_file_stats_(const char *filename, struct stat *stats)
270 struct utimbuf srctime;
272 FLAC__ASSERT(0 != filename);
273 FLAC__ASSERT(0 != stats);
275 srctime.actime = stats->st_atime;
276 srctime.modtime = stats->st_mtime;
277 (void)chmod(filename, stats->st_mode);
278 (void)utime(filename, &srctime);
279 #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
280 FLAC_CHECK_RETURN(chown(filename, stats->st_uid, (gid_t)(-1)));
281 FLAC_CHECK_RETURN(chown(filename, (uid_t)(-1), stats->st_gid));
282 #endif
285 #ifdef FLAC__VALGRIND_TESTING
286 static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
288 FILE *stream = (FILE*)handle;
289 size_t ret = fwrite(ptr, size, nmemb, stream);
290 if(!ferror(stream))
291 fflush(stream);
292 return ret;
294 #endif
296 static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
298 FLAC__off_t o = (FLAC__off_t)offset;
299 FLAC__ASSERT(offset == o);
300 return fseeko((FILE*)handle, o, whence);
303 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
305 return ftello((FILE*)handle);
308 static int chain_eof_cb_(::FLAC__IOHandle handle)
310 return feof((FILE*)handle);
313 static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
315 if(filename_based)
316 return chain.write(use_padding, preserve_file_stats);
317 else {
318 ::FLAC__IOCallbacks callbacks;
320 memset(&callbacks, 0, sizeof(callbacks));
321 callbacks.read = (::FLAC__IOCallback_Read)fread;
322 #ifdef FLAC__VALGRIND_TESTING
323 callbacks.write = chain_write_cb_;
324 #else
325 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
326 #endif
327 callbacks.seek = chain_seek_cb_;
328 callbacks.eof = chain_eof_cb_;
330 if(chain.check_if_tempfile_needed(use_padding)) {
331 struct stat stats;
332 FILE *file, *tempfile;
333 char *tempfilename;
334 if(preserve_file_stats) {
335 if(!get_file_stats_(filename, &stats))
336 return false;
338 if(0 == (file = fopen(filename, "rb")))
339 return false; /*@@@@ chain status still says OK though */
340 if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
341 fclose(file);
342 cleanup_tempfile_(&tempfile, &tempfilename);
343 return false; /*@@@@ chain status still says OK though */
345 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
346 fclose(file);
347 fclose(tempfile);
348 return false;
350 fclose(file);
351 fclose(tempfile);
352 file = tempfile = 0;
353 if(!transport_tempfile_(filename, &tempfile, &tempfilename))
354 return false;
355 if(preserve_file_stats)
356 set_file_stats_(filename, &stats);
358 else {
359 FILE *file = fopen(filename, "r+b");
360 if(0 == file)
361 return false; /*@@@@ chain status still says OK though */
362 if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks)) {
363 fclose(file);
364 return false;
366 fclose(file);
370 return true;
373 static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg)
375 if(filename_based)
376 return chain.read(filename, is_ogg);
377 else {
378 ::FLAC__IOCallbacks callbacks;
380 memset(&callbacks, 0, sizeof(callbacks));
381 callbacks.read = (::FLAC__IOCallback_Read)fread;
382 callbacks.seek = chain_seek_cb_;
383 callbacks.tell = chain_tell_cb_;
386 bool ret;
387 FILE *file = fopen(filename, "rb");
388 if(0 == file)
389 return false; /*@@@@ chain status still says OK though */
390 ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg);
391 fclose(file);
392 return ret;
397 /* function for comparing our metadata to a FLAC::Metadata::Chain */
399 static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
401 unsigned i;
402 FLAC::Metadata::Iterator iterator;
403 bool next_ok = true;
405 printf("\tcomparing chain... ");
406 fflush(stdout);
408 if(!iterator.is_valid())
409 return die_("allocating memory for iterator");
411 iterator.init(chain);
413 i = 0;
414 do {
415 FLAC::Metadata::Prototype *block;
417 printf("%u... ", i);
418 fflush(stdout);
420 if(0 == (block = iterator.get_block()))
421 return die_("getting block from iterator");
423 if(*block != *our_metadata_.blocks[i])
424 return die_("metadata block mismatch");
426 delete block;
427 i++;
428 next_ok = iterator.next();
429 } while(i < our_metadata_.num_blocks && next_ok);
431 if(next_ok)
432 return die_("chain has more blocks than expected");
434 if(i < our_metadata_.num_blocks)
435 return die_("short block count in chain");
437 if(0 != current_block) {
438 printf("CURRENT_POSITION... ");
439 fflush(stdout);
441 if(*current_block != *our_metadata_.blocks[current_position])
442 return die_("metadata block mismatch");
445 printf("PASSED\n");
447 return true;
450 ::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
452 (void)buffer;
455 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
456 (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
458 printf("content... ");
459 fflush(stdout);
462 return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
465 void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
467 /* don't bother checking if we've already hit an error */
468 if(error_occurred_)
469 return;
471 printf("%d... ", mc_our_block_number_);
472 fflush(stdout);
474 if(!ignore_metadata_) {
475 if(mc_our_block_number_ >= our_metadata_.num_blocks) {
476 (void)die_("got more metadata blocks than expected");
477 error_occurred_ = true;
479 else {
480 if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
481 (void)die_("metadata block mismatch");
482 error_occurred_ = true;
487 mc_our_block_number_++;
490 void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
492 error_occurred_ = true;
493 printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
496 static bool generate_file_(bool include_extras, bool is_ogg)
498 ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
499 ::FLAC__StreamMetadata *metadata[4];
500 unsigned i = 0, n = 0;
502 printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
504 while(our_metadata_.num_blocks > 0)
505 delete_from_our_metadata_(0);
507 streaminfo.is_last = false;
508 streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO;
509 streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
510 streaminfo.data.stream_info.min_blocksize = 576;
511 streaminfo.data.stream_info.max_blocksize = 576;
512 streaminfo.data.stream_info.min_framesize = 0;
513 streaminfo.data.stream_info.max_framesize = 0;
514 streaminfo.data.stream_info.sample_rate = 44100;
515 streaminfo.data.stream_info.channels = 1;
516 streaminfo.data.stream_info.bits_per_sample = 8;
517 streaminfo.data.stream_info.total_samples = 0;
518 memset(streaminfo.data.stream_info.md5sum, 0, 16);
521 const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
522 vorbiscomment.is_last = false;
523 vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
524 vorbiscomment.length = (4 + vendor_string_length) + 4;
525 vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
526 vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
527 memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
528 vorbiscomment.data.vorbis_comment.num_comments = 0;
529 vorbiscomment.data.vorbis_comment.comments = 0;
533 if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
534 return die_("priming our metadata");
535 cuesheet->is_last = false;
536 strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
537 cuesheet->data.cue_sheet.lead_in = 123;
538 cuesheet->data.cue_sheet.is_cd = false;
539 if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
540 return die_("priming our metadata");
541 cuesheet->data.cue_sheet.tracks[0].number = 1;
542 if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
543 return die_("priming our metadata");
547 picture.is_last = false;
548 picture.type = ::FLAC__METADATA_TYPE_PICTURE;
549 picture.length =
551 FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
552 FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
553 FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
554 FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
555 FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
556 FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
557 FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
558 FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
559 ) / 8
561 picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
562 picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
563 picture.length += strlen(picture.data.picture.mime_type);
564 picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
565 picture.length += strlen((const char *)picture.data.picture.description);
566 picture.data.picture.width = 300;
567 picture.data.picture.height = 300;
568 picture.data.picture.depth = 24;
569 picture.data.picture.colors = 0;
570 picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
571 picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
572 picture.length += picture.data.picture.data_length;
575 padding.is_last = true;
576 padding.type = ::FLAC__METADATA_TYPE_PADDING;
577 padding.length = 1234;
579 metadata[n++] = &vorbiscomment;
580 if(include_extras) {
581 metadata[n++] = cuesheet;
582 metadata[n++] = &picture;
584 metadata[n++] = &padding;
586 FLAC::Metadata::StreamInfo s(&streaminfo);
587 FLAC::Metadata::VorbisComment v(&vorbiscomment);
588 FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
589 FLAC::Metadata::Picture pi(&picture);
590 FLAC::Metadata::Padding p(&padding);
592 !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
593 !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
594 (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
595 (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
596 !insert_to_our_metadata_(&p, i++, /*copy=*/true)
598 return die_("priming our metadata");
600 if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
601 return die_("creating the encoded file");
603 free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
604 free(picture.data.picture.mime_type);
605 free(picture.data.picture.description);
606 free(picture.data.picture.data);
608 return true;
611 static bool test_file_(bool is_ogg, bool ignore_metadata)
613 const char *filename = flacfilename(is_ogg);
614 OurFileDecoder decoder(ignore_metadata);
616 mc_our_block_number_ = 0;
617 decoder.error_occurred_ = false;
619 printf("\ttesting '%s'... ", filename);
620 fflush(stdout);
622 if(!decoder.is_valid())
623 return die_("couldn't allocate decoder instance");
625 decoder.set_md5_checking(true);
626 decoder.set_metadata_respond_all();
627 if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
628 (void)decoder.finish();
629 return die_("initializing decoder\n");
631 if(!decoder.process_until_end_of_stream()) {
632 (void)decoder.finish();
633 return die_("decoding file\n");
636 (void)decoder.finish();
638 if(decoder.error_occurred_)
639 return false;
641 if(mc_our_block_number_ != our_metadata_.num_blocks)
642 return die_("short metadata block count");
644 printf("PASSED\n");
645 return true;
648 static bool change_stats_(const char *filename, bool read_only)
650 if(!grabbag__file_change_stats(filename, read_only))
651 return die_("during grabbag__file_change_stats()");
653 return true;
656 static bool remove_file_(const char *filename)
658 while(our_metadata_.num_blocks > 0)
659 delete_from_our_metadata_(0);
661 if(!grabbag__file_remove_file(filename))
662 return die_("removing file");
664 return true;
667 static bool test_level_0_()
669 FLAC::Metadata::StreamInfo streaminfo;
671 printf("\n\n++++++ testing level 0 interface\n");
673 if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
674 return false;
676 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
677 return false;
679 printf("testing FLAC::Metadata::get_streaminfo()... ");
681 if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
682 return die_("during FLAC::Metadata::get_streaminfo()");
684 /* check to see if some basic data matches (c.f. generate_file_()) */
685 if(streaminfo.get_channels() != 1)
686 return die_("mismatch in streaminfo.get_channels()");
687 if(streaminfo.get_bits_per_sample() != 8)
688 return die_("mismatch in streaminfo.get_bits_per_sample()");
689 if(streaminfo.get_sample_rate() != 44100)
690 return die_("mismatch in streaminfo.get_sample_rate()");
691 if(streaminfo.get_min_blocksize() != 576)
692 return die_("mismatch in streaminfo.get_min_blocksize()");
693 if(streaminfo.get_max_blocksize() != 576)
694 return die_("mismatch in streaminfo.get_max_blocksize()");
696 printf("OK\n");
699 printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
701 FLAC::Metadata::VorbisComment *tags = 0;
703 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
704 return die_("during FLAC::Metadata::get_tags()");
706 /* check to see if some basic data matches (c.f. generate_file_()) */
707 if(tags->get_num_comments() != 0)
708 return die_("mismatch in tags->get_num_comments()");
710 printf("OK\n");
712 delete tags;
716 printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
718 FLAC::Metadata::VorbisComment tags;
720 if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
721 return die_("during FLAC::Metadata::get_tags()");
723 /* check to see if some basic data matches (c.f. generate_file_()) */
724 if(tags.get_num_comments() != 0)
725 return die_("mismatch in tags.get_num_comments()");
727 printf("OK\n");
731 printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
733 FLAC::Metadata::CueSheet *cuesheet = 0;
735 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
736 return die_("during FLAC::Metadata::get_cuesheet()");
738 /* check to see if some basic data matches (c.f. generate_file_()) */
739 if(cuesheet->get_lead_in() != 123)
740 return die_("mismatch in cuesheet->get_lead_in()");
742 printf("OK\n");
744 delete cuesheet;
748 printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
750 FLAC::Metadata::CueSheet cuesheet;
752 if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
753 return die_("during FLAC::Metadata::get_cuesheet()");
755 /* check to see if some basic data matches (c.f. generate_file_()) */
756 if(cuesheet.get_lead_in() != 123)
757 return die_("mismatch in cuesheet.get_lead_in()");
759 printf("OK\n");
763 printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
765 FLAC::Metadata::Picture *picture = 0;
767 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)))
768 return die_("during FLAC::Metadata::get_picture()");
770 /* check to see if some basic data matches (c.f. generate_file_()) */
771 if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
772 return die_("mismatch in picture->get_type ()");
774 printf("OK\n");
776 delete picture;
780 printf("testing FLAC::Metadata::get_picture(Picture &)... ");
782 FLAC::Metadata::Picture picture;
784 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)))
785 return die_("during FLAC::Metadata::get_picture()");
787 /* check to see if some basic data matches (c.f. generate_file_()) */
788 if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
789 return die_("mismatch in picture->get_type ()");
791 printf("OK\n");
794 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
795 return false;
797 return true;
800 static bool test_level_1_()
802 FLAC::Metadata::Prototype *block;
803 FLAC::Metadata::StreamInfo *streaminfo;
804 FLAC::Metadata::Padding *padding;
805 FLAC::Metadata::Application *app;
806 FLAC__byte data[1000];
807 unsigned our_current_position = 0;
809 // initialize 'data' to avoid Valgrind errors
810 memset(data, 0, sizeof(data));
812 printf("\n\n++++++ testing level 1 interface\n");
814 /************************************************************/
816 printf("simple iterator on read-only file\n");
818 if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
819 return false;
821 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
822 return false;
824 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
825 return false;
827 FLAC::Metadata::SimpleIterator iterator;
829 if(!iterator.is_valid())
830 return die_("iterator.is_valid() returned false");
832 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
833 return die_("iterator.init() returned false");
835 printf("is writable = %u\n", (unsigned)iterator.is_writable());
836 if(iterator.is_writable())
837 return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
839 printf("iterate forwards\n");
841 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
842 return die_("expected STREAMINFO type from iterator.get_block_type()");
843 if(0 == (block = iterator.get_block()))
844 return die_("getting block 0");
845 if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
846 return die_("expected STREAMINFO type");
847 if(block->get_is_last())
848 return die_("expected is_last to be false");
849 if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
850 return die_("bad STREAMINFO length");
851 /* check to see if some basic data matches (c.f. generate_file_()) */
852 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
853 FLAC__ASSERT(0 != streaminfo);
854 if(streaminfo->get_channels() != 1)
855 return die_("mismatch in channels");
856 if(streaminfo->get_bits_per_sample() != 8)
857 return die_("mismatch in bits_per_sample");
858 if(streaminfo->get_sample_rate() != 44100)
859 return die_("mismatch in sample_rate");
860 if(streaminfo->get_min_blocksize() != 576)
861 return die_("mismatch in min_blocksize");
862 if(streaminfo->get_max_blocksize() != 576)
863 return die_("mismatch in max_blocksize");
864 // we will delete streaminfo a little later when we're really done with it...
866 if(!iterator.next())
867 return die_("forward iterator ended early");
868 our_current_position++;
870 if(!iterator.next())
871 return die_("forward iterator ended early");
872 our_current_position++;
874 if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
875 return die_("expected PADDING type from iterator.get_block_type()");
876 if(0 == (block = iterator.get_block()))
877 return die_("getting block 1");
878 if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
879 return die_("expected PADDING type");
880 if(!block->get_is_last())
881 return die_("expected is_last to be true");
882 /* check to see if some basic data matches (c.f. generate_file_()) */
883 if(block->get_length() != 1234)
884 return die_("bad PADDING length");
885 delete block;
887 if(iterator.next())
888 return die_("forward iterator returned true but should have returned false");
890 printf("iterate backwards\n");
891 if(!iterator.prev())
892 return die_("reverse iterator ended early");
893 if(!iterator.prev())
894 return die_("reverse iterator ended early");
895 if(iterator.prev())
896 return die_("reverse iterator returned true but should have returned false");
898 printf("testing iterator.set_block() on read-only file...\n");
900 if(!iterator.set_block(streaminfo, false))
901 printf("PASSED. iterator.set_block() returned false like it should\n");
902 else
903 return die_("iterator.set_block() returned true but shouldn't have");
904 delete streaminfo;
907 /************************************************************/
909 printf("simple iterator on writable file\n");
911 if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
912 return false;
914 printf("creating APPLICATION block\n");
916 if(0 == (app = new FLAC::Metadata::Application()))
917 return die_("new FLAC::Metadata::Application()");
918 app->set_id((const unsigned char *)"duh");
920 printf("creating PADDING block\n");
922 if(0 == (padding = new FLAC::Metadata::Padding()))
923 return die_("new FLAC::Metadata::Padding()");
924 padding->set_length(20);
926 FLAC::Metadata::SimpleIterator iterator;
928 if(!iterator.is_valid())
929 return die_("iterator.is_valid() returned false");
931 if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
932 return die_("iterator.init() returned false");
933 our_current_position = 0;
935 printf("is writable = %u\n", (unsigned)iterator.is_writable());
937 printf("[S]VP\ttry to write over STREAMINFO block...\n");
938 if(!iterator.set_block(app, false))
939 printf("\titerator.set_block() returned false like it should\n");
940 else
941 return die_("iterator.set_block() returned true but shouldn't have");
943 printf("[S]VP\tnext\n");
944 if(!iterator.next())
945 return die_("iterator ended early\n");
946 our_current_position++;
948 printf("S[V]P\tnext\n");
949 if(!iterator.next())
950 return die_("iterator ended early\n");
951 our_current_position++;
953 printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
954 padding->set_length(25);
955 if(!iterator.insert_block_after(padding, false))
956 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
957 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
958 return false;
960 printf("SVP[P]\tprev\n");
961 if(!iterator.prev())
962 return die_("iterator ended early\n");
963 our_current_position--;
965 printf("SV[P]P\tprev\n");
966 if(!iterator.prev())
967 return die_("iterator ended early\n");
968 our_current_position--;
970 printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
971 padding->set_length(30);
972 if(!iterator.insert_block_after(padding, false))
973 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
974 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
975 return false;
977 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
978 return false;
980 printf("SV[P]PP\tprev\n");
981 if(!iterator.prev())
982 return die_("iterator ended early\n");
983 our_current_position--;
985 printf("S[V]PPP\tprev\n");
986 if(!iterator.prev())
987 return die_("iterator ended early\n");
988 our_current_position--;
990 printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
991 if(iterator.delete_block(false))
992 return die_ss_("iterator.delete_block(false) should have returned false", iterator);
994 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
995 return false;
997 printf("[S]VPPP\tnext\n");
998 if(!iterator.next())
999 return die_("iterator ended early\n");
1000 our_current_position++;
1002 printf("S[V]PPP\tnext\n");
1003 if(!iterator.next())
1004 return die_("iterator ended early\n");
1005 our_current_position++;
1007 printf("SV[P]PP\tdelete (middle block), replace with padding\n");
1008 if(!iterator.delete_block(true))
1009 return die_ss_("iterator.delete_block(true)", iterator);
1010 our_current_position--;
1012 printf("S[V]PPP\tnext\n");
1013 if(!iterator.next())
1014 return die_("iterator ended early\n");
1015 our_current_position++;
1017 printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
1018 if(!iterator.delete_block(false))
1019 return die_ss_("iterator.delete_block(false)", iterator);
1020 delete_from_our_metadata_(our_current_position--);
1022 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1023 return false;
1025 printf("S[V]PP\tnext\n");
1026 if(!iterator.next())
1027 return die_("iterator ended early\n");
1028 our_current_position++;
1030 printf("SV[P]P\tnext\n");
1031 if(!iterator.next())
1032 return die_("iterator ended early\n");
1033 our_current_position++;
1035 printf("SVP[P]\tdelete (last block), replace with padding\n");
1036 if(!iterator.delete_block(true))
1037 return die_ss_("iterator.delete_block(false)", iterator);
1038 our_current_position--;
1040 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1041 return false;
1043 printf("SV[P]P\tnext\n");
1044 if(!iterator.next())
1045 return die_("iterator ended early\n");
1046 our_current_position++;
1048 printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1049 if(!iterator.delete_block(false))
1050 return die_ss_("iterator.delete_block(false)", iterator);
1051 delete_from_our_metadata_(our_current_position--);
1053 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1054 return false;
1056 printf("SV[P]\tprev\n");
1057 if(!iterator.prev())
1058 return die_("iterator ended early\n");
1059 our_current_position--;
1061 printf("S[V]P\tprev\n");
1062 if(!iterator.prev())
1063 return die_("iterator ended early\n");
1064 our_current_position--;
1066 printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1067 FLAC__ASSERT(our_current_position == 0);
1068 block = iterator.get_block();
1069 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1070 FLAC__ASSERT(0 != streaminfo);
1071 streaminfo->set_sample_rate(32000);
1072 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1073 return die_("copying object");
1074 if(!iterator.set_block(block, false))
1075 return die_ss_("iterator.set_block(block, false)", iterator);
1076 delete block;
1078 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1079 return false;
1081 printf("[S]VP\tnext\n");
1082 if(!iterator.next())
1083 return die_("iterator ended early\n");
1084 our_current_position++;
1086 printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1087 app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
1088 if(!iterator.insert_block_after(app, true))
1089 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1090 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1091 return false;
1092 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1094 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1095 return false;
1097 printf("SV[A]P\tnext\n");
1098 if(!iterator.next())
1099 return die_("iterator ended early\n");
1100 our_current_position++;
1102 printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1103 app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
1104 if(!iterator.set_block(app, true))
1105 return die_ss_("iterator.set_block(app, true)", iterator);
1106 if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1107 return false;
1108 add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
1110 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1111 return false;
1113 printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1114 app->set_id((const unsigned char *)"guh"); /* twiddle the id */
1115 if(!app->set_data(data, sizeof(data), true))
1116 return die_("setting APPLICATION data");
1117 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1118 return die_("copying object");
1119 if(!iterator.set_block(app, false))
1120 return die_ss_("iterator.set_block(app, false)", iterator);
1122 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1123 return false;
1125 printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1126 app->set_id((const unsigned char *)"huh"); /* twiddle the id */
1127 if(!app->set_data(data, 12, true))
1128 return die_("setting APPLICATION data");
1129 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1130 return die_("copying object");
1131 if(!iterator.set_block(app, false))
1132 return die_ss_("iterator.set_block(app, false)", iterator);
1134 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1135 return false;
1137 printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1138 app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
1139 if(!app->set_data(data, sizeof(data), true))
1140 return die_("setting APPLICATION data");
1141 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1142 return die_("copying object");
1143 add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
1144 if(!iterator.set_block(app, true))
1145 return die_ss_("iterator.set_block(app, true)", iterator);
1147 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1148 return false;
1150 printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1151 app->set_id((const unsigned char *)"juh"); /* twiddle the id */
1152 if(!app->set_data(data, 23, true))
1153 return die_("setting APPLICATION data");
1154 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1155 return die_("copying object");
1156 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1157 return die_("copying object");
1158 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
1159 if(!iterator.set_block(app, true))
1160 return die_ss_("iterator.set_block(app, true)", iterator);
1162 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1163 return false;
1165 printf("SVA[A]PP\tnext\n");
1166 if(!iterator.next())
1167 return die_("iterator ended early\n");
1168 our_current_position++;
1170 printf("SVAA[P]P\tnext\n");
1171 if(!iterator.next())
1172 return die_("iterator ended early\n");
1173 our_current_position++;
1175 printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1176 padding->set_length(5);
1177 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1178 return die_("copying object");
1179 if(!iterator.set_block(padding, false))
1180 return die_ss_("iterator.set_block(padding, false)", iterator);
1182 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1183 return false;
1185 printf("SVAAP[P]\tset APPLICATION (grow)\n");
1186 app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
1187 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1188 return die_("copying object");
1189 if(!iterator.set_block(app, false))
1190 return die_ss_("iterator.set_block(app, false)", iterator);
1192 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1193 return false;
1195 printf("SVAAP[A]\tset PADDING (equal)\n");
1196 padding->set_length(27);
1197 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1198 return die_("copying object");
1199 if(!iterator.set_block(padding, false))
1200 return die_ss_("iterator.set_block(padding, false)", iterator);
1202 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1203 return false;
1205 printf("SVAAP[P]\tprev\n");
1206 if(!iterator.prev())
1207 return die_("iterator ended early\n");
1208 our_current_position--;
1210 printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1211 if(!iterator.delete_block(false))
1212 return die_ss_("iterator.delete_block(false)", iterator);
1213 delete_from_our_metadata_(our_current_position--);
1215 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1216 return false;
1218 printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1219 if(!iterator.delete_block(false))
1220 return die_ss_("iterator.delete_block(false)", iterator);
1221 delete_from_our_metadata_(our_current_position--);
1223 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1224 return false;
1226 printf("SV[A]P\tnext\n");
1227 if(!iterator.next())
1228 return die_("iterator ended early\n");
1229 our_current_position++;
1231 printf("SVA[P]\tinsert PADDING after\n");
1232 padding->set_length(5);
1233 if(!iterator.insert_block_after(padding, false))
1234 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1235 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1236 return false;
1238 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1239 return false;
1241 printf("SVAP[P]\tprev\n");
1242 if(!iterator.prev())
1243 return die_("iterator ended early\n");
1244 our_current_position--;
1246 printf("SVA[P]P\tprev\n");
1247 if(!iterator.prev())
1248 return die_("iterator ended early\n");
1249 our_current_position--;
1251 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1252 if(!app->set_data(data, 32, true))
1253 return die_("setting APPLICATION data");
1254 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1255 return die_("copying object");
1256 if(!iterator.set_block(app, true))
1257 return die_ss_("iterator.set_block(app, true)", iterator);
1259 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1260 return false;
1262 printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1263 if(!app->set_data(data, 60, true))
1264 return die_("setting APPLICATION data");
1265 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1266 return die_("copying object");
1267 if(!iterator.set_block(app, true))
1268 return die_ss_("iterator.set_block(app, true)", iterator);
1270 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1271 return false;
1273 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1274 if(!app->set_data(data, 87, true))
1275 return die_("setting APPLICATION data");
1276 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1277 return die_("copying object");
1278 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1279 if(!iterator.set_block(app, true))
1280 return die_ss_("iterator.set_block(app, true)", iterator);
1282 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1283 return false;
1285 printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1286 if(!app->set_data(data, 91, true))
1287 return die_("setting APPLICATION data");
1288 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1289 return die_("copying object");
1290 delete_from_our_metadata_(our_current_position+1);
1291 if(!iterator.set_block(app, true))
1292 return die_ss_("iterator.set_block(app, true)", iterator);
1294 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1295 return false;
1297 printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1298 if(!app->set_data(data, 100, true))
1299 return die_("setting APPLICATION data");
1300 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1301 return die_("copying object");
1302 delete_from_our_metadata_(our_current_position+1);
1303 our_metadata_.blocks[our_current_position]->set_is_last(true);
1304 if(!iterator.set_block(app, true))
1305 return die_ss_("iterator.set_block(app, true)", iterator);
1307 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1308 return false;
1310 printf("SV[A]\tset PADDING (equal size)\n");
1311 padding->set_length(app->get_length());
1312 if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1313 return die_("copying object");
1314 if(!iterator.set_block(padding, true))
1315 return die_ss_("iterator.set_block(padding, true)", iterator);
1317 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1318 return false;
1320 printf("SV[P]\tinsert PADDING after\n");
1321 if(!iterator.insert_block_after(padding, false))
1322 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1323 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1324 return false;
1326 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1327 return false;
1329 printf("SVP[P]\tinsert PADDING after\n");
1330 padding->set_length(5);
1331 if(!iterator.insert_block_after(padding, false))
1332 return die_ss_("iterator.insert_block_after(padding, false)", iterator);
1333 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1334 return false;
1336 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1337 return false;
1339 printf("SVPP[P]\tprev\n");
1340 if(!iterator.prev())
1341 return die_("iterator ended early\n");
1342 our_current_position--;
1344 printf("SVP[P]P\tprev\n");
1345 if(!iterator.prev())
1346 return die_("iterator ended early\n");
1347 our_current_position--;
1349 printf("SV[P]PP\tprev\n");
1350 if(!iterator.prev())
1351 return die_("iterator ended early\n");
1352 our_current_position--;
1354 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1355 if(!app->set_data(data, 101, true))
1356 return die_("setting APPLICATION data");
1357 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1358 return die_("copying object");
1359 if(!iterator.insert_block_after(app, true))
1360 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1362 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1363 return false;
1365 printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1366 if(!iterator.delete_block(false))
1367 return die_ss_("iterator.delete_block(false)", iterator);
1368 delete_from_our_metadata_(our_current_position--);
1370 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1371 return false;
1373 printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1374 if(!app->set_data(data, 97, 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);
1381 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1382 return false;
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--);
1389 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1390 return false;
1392 printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1393 if(!app->set_data(data, 100, 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 delete_from_our_metadata_(our_current_position+1);
1398 if(!iterator.insert_block_after(app, true))
1399 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1401 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1402 return false;
1404 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1405 if(!iterator.delete_block(false))
1406 return die_ss_("iterator.delete_block(false)", iterator);
1407 delete_from_our_metadata_(our_current_position--);
1409 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1410 return false;
1412 printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1413 if(!app->set_data(data, 96, true))
1414 return die_("setting APPLICATION data");
1415 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1416 return die_("copying object");
1417 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
1418 if(!iterator.insert_block_after(app, true))
1419 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1421 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1422 return false;
1424 printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1425 if(!iterator.delete_block(false))
1426 return die_ss_("iterator.delete_block(false)", iterator);
1427 delete_from_our_metadata_(our_current_position--);
1429 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1430 return false;
1432 printf("S[V]PP\tnext\n");
1433 if(!iterator.next())
1434 return die_("iterator ended early\n");
1435 our_current_position++;
1437 printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1438 if(!iterator.delete_block(false))
1439 return die_ss_("iterator.delete_block(false)", iterator);
1440 delete_from_our_metadata_(our_current_position--);
1442 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1443 return false;
1445 printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1446 if(!app->set_data(data, 1, true))
1447 return die_("setting APPLICATION data");
1448 if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1449 return die_("copying object");
1450 delete_from_our_metadata_(our_current_position+1);
1451 if(!iterator.insert_block_after(app, true))
1452 return die_ss_("iterator.insert_block_after(app, true)", iterator);
1454 if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
1455 return false;
1458 delete app;
1459 delete padding;
1461 if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1462 return false;
1464 return true;
1467 static bool test_level_2_(bool filename_based, bool is_ogg)
1469 FLAC::Metadata::Prototype *block;
1470 FLAC::Metadata::StreamInfo *streaminfo;
1471 FLAC::Metadata::Application *app;
1472 FLAC::Metadata::Padding *padding;
1473 FLAC__byte data[2000];
1474 unsigned our_current_position;
1476 // initialize 'data' to avoid Valgrind errors
1477 memset(data, 0, sizeof(data));
1479 printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1481 printf("generate read-only file\n");
1483 if(!generate_file_(/*include_extras=*/false, is_ogg))
1484 return false;
1486 if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1487 return false;
1489 printf("create chain\n");
1490 FLAC::Metadata::Chain chain;
1491 if(!chain.is_valid())
1492 return die_("allocating memory for chain");
1494 printf("read chain\n");
1496 if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1497 return die_c_("reading chain", chain.status());
1499 printf("[S]VP\ttest initial metadata\n");
1501 if(!compare_chain_(chain, 0, 0))
1502 return false;
1503 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1504 return false;
1506 if(is_ogg)
1507 goto end;
1509 printf("switch file to read-write\n");
1511 if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1512 return false;
1514 printf("create iterator\n");
1516 FLAC::Metadata::Iterator iterator;
1517 if(!iterator.is_valid())
1518 return die_("allocating memory for iterator");
1520 our_current_position = 0;
1522 iterator.init(chain);
1524 if(0 == (block = iterator.get_block()))
1525 return die_("getting block from iterator");
1527 FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
1529 printf("[S]VP\tmodify STREAMINFO, write\n");
1531 streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
1532 FLAC__ASSERT(0 != streaminfo);
1533 streaminfo->set_sample_rate(32000);
1534 if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1535 return die_("copying object");
1536 delete block;
1538 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1539 return die_c_("during chain.write(false, true)", chain.status());
1540 block = iterator.get_block();
1541 if(!compare_chain_(chain, our_current_position, block))
1542 return false;
1543 delete block;
1544 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1545 return false;
1547 printf("[S]VP\tnext\n");
1548 if(!iterator.next())
1549 return die_("iterator ended early\n");
1550 our_current_position++;
1552 printf("S[V]P\tnext\n");
1553 if(!iterator.next())
1554 return die_("iterator ended early\n");
1555 our_current_position++;
1557 printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1558 if(0 == (block = iterator.get_block()))
1559 return die_("getting block from iterator");
1560 if(0 == (app = new FLAC::Metadata::Application()))
1561 return die_("new FLAC::Metadata::Application()");
1562 app->set_id((const unsigned char *)"duh");
1563 if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1564 return die_("setting APPLICATION data");
1565 delete block;
1566 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1567 return die_("copying object");
1568 if(!iterator.set_block(app))
1569 return die_c_("iterator.set_block(app)", chain.status());
1571 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1572 return die_c_("during chain.write(false, false)", chain.status());
1573 block = iterator.get_block();
1574 if(!compare_chain_(chain, our_current_position, block))
1575 return false;
1576 delete block;
1577 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1578 return false;
1580 printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1581 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1582 return die_("copying object");
1583 if(!app->set_data(data, 26, true))
1584 return die_("setting APPLICATION data");
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());
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;
1599 printf("SV[A]\tgrow 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, 28, 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());
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;
1618 printf("SV[A]\tgrow APPLICATION, use padding, but last block is not 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, 36, 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());
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;
1637 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\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, 33, 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());
1647 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1648 return die_c_("during chain.write(true, 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;
1656 printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1657 if(0 == (padding = new FLAC::Metadata::Padding()))
1658 return die_("creating PADDING block");
1659 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1660 return die_("copying object");
1661 if(!app->set_data(data, 29, true))
1662 return die_("setting APPLICATION data");
1663 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1664 return die_("copying object");
1665 padding->set_length(0);
1666 if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1667 return die_("internal error");
1668 if(!iterator.set_block(app))
1669 return die_c_("iterator.set_block(app)", chain.status());
1671 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1672 return die_c_("during chain.write(true, false)", chain.status());
1673 block = iterator.get_block();
1674 if(!compare_chain_(chain, our_current_position, block))
1675 return false;
1676 delete block;
1677 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1678 return false;
1680 printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1681 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1682 return die_("copying object");
1683 if(!app->set_data(data, 16, true))
1684 return die_("setting APPLICATION data");
1685 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1686 return die_("copying object");
1687 dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
1688 if(!iterator.set_block(app))
1689 return die_c_("iterator.set_block(app)", chain.status());
1691 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1692 return die_c_("during chain.write(true, false)", chain.status());
1693 block = iterator.get_block();
1694 if(!compare_chain_(chain, our_current_position, block))
1695 return false;
1696 delete block;
1697 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1698 return false;
1700 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1701 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1702 return die_("copying object");
1703 if(!app->set_data(data, 50, true))
1704 return die_("setting APPLICATION data");
1705 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1706 return die_("copying object");
1707 if(!iterator.set_block(app))
1708 return die_c_("iterator.set_block(app)", chain.status());
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;
1719 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\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, 56, 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 add_to_padding_length_(our_current_position+1, -(56 - 50));
1727 if(!iterator.set_block(app))
1728 return die_c_("iterator.set_block(app)", chain.status());
1730 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1731 return die_c_("during chain.write(true, false)", chain.status());
1732 block = iterator.get_block();
1733 if(!compare_chain_(chain, our_current_position, block))
1734 return false;
1735 delete block;
1736 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1737 return false;
1739 printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1740 if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1741 return die_("copying object");
1742 if(!app->set_data(data, 67, true))
1743 return die_("setting APPLICATION data");
1744 if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1745 return die_("copying object");
1746 delete_from_our_metadata_(our_current_position+1);
1747 if(!iterator.set_block(app))
1748 return die_c_("iterator.set_block(app)", chain.status());
1750 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1751 return die_c_("during chain.write(true, false)", chain.status());
1752 block = iterator.get_block();
1753 if(!compare_chain_(chain, our_current_position, block))
1754 return false;
1755 delete block;
1756 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1757 return false;
1759 printf("SV[A]\tprev\n");
1760 if(!iterator.prev())
1761 return die_("iterator ended early\n");
1762 our_current_position--;
1764 printf("S[V]A\tprev\n");
1765 if(!iterator.prev())
1766 return die_("iterator ended early\n");
1767 our_current_position--;
1769 printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1770 if(0 == (padding = new FLAC::Metadata::Padding()))
1771 return die_("creating PADDING block");
1772 padding->set_length(30);
1773 if(!iterator.insert_block_before(padding))
1774 printf("\titerator.insert_block_before() returned false like it should\n");
1775 else
1776 return die_("iterator.insert_block_before() should have returned false");
1778 printf("[S]VA\tnext\n");
1779 if(!iterator.next())
1780 return die_("iterator ended early\n");
1781 our_current_position++;
1783 printf("S[V]A\tinsert PADDING after\n");
1784 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1785 return die_("copying metadata");
1786 if(!iterator.insert_block_after(padding))
1787 return die_("iterator.insert_block_after(padding)");
1789 block = iterator.get_block();
1790 if(!compare_chain_(chain, our_current_position, block))
1791 return false;
1792 delete block;
1794 printf("SV[P]A\tinsert PADDING before\n");
1795 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1796 return die_("creating PADDING block");
1797 padding->set_length(17);
1798 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1799 return die_("copying metadata");
1800 if(!iterator.insert_block_before(padding))
1801 return die_("iterator.insert_block_before(padding)");
1803 block = iterator.get_block();
1804 if(!compare_chain_(chain, our_current_position, block))
1805 return false;
1806 delete block;
1808 printf("SV[P]PA\tinsert PADDING before\n");
1809 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
1810 return die_("creating PADDING block");
1811 padding->set_length(0);
1812 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1813 return die_("copying metadata");
1814 if(!iterator.insert_block_before(padding))
1815 return die_("iterator.insert_block_before(padding)");
1817 block = iterator.get_block();
1818 if(!compare_chain_(chain, our_current_position, block))
1819 return false;
1820 delete block;
1822 printf("SV[P]PPA\tnext\n");
1823 if(!iterator.next())
1824 return die_("iterator ended early\n");
1825 our_current_position++;
1827 printf("SVP[P]PA\tnext\n");
1828 if(!iterator.next())
1829 return die_("iterator ended early\n");
1830 our_current_position++;
1832 printf("SVPP[P]A\tnext\n");
1833 if(!iterator.next())
1834 return die_("iterator ended early\n");
1835 our_current_position++;
1837 printf("SVPPP[A]\tinsert PADDING after\n");
1838 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1839 return die_("creating PADDING block");
1840 padding->set_length(57);
1841 if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1842 return die_("copying metadata");
1843 if(!iterator.insert_block_after(padding))
1844 return die_("iterator.insert_block_after(padding)");
1846 block = iterator.get_block();
1847 if(!compare_chain_(chain, our_current_position, block))
1848 return false;
1849 delete block;
1851 printf("SVPPPA[P]\tinsert PADDING before\n");
1852 if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
1853 return die_("creating PADDING block");
1854 padding->set_length(99);
1855 if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1856 return die_("copying metadata");
1857 if(!iterator.insert_block_before(padding))
1858 return die_("iterator.insert_block_before(padding)");
1860 block = iterator.get_block();
1861 if(!compare_chain_(chain, our_current_position, block))
1862 return false;
1863 delete block;
1866 our_current_position = 0;
1868 printf("SVPPPAPP\tmerge padding\n");
1869 chain.merge_padding();
1870 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
1871 add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
1872 add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
1873 delete_from_our_metadata_(7);
1874 delete_from_our_metadata_(4);
1875 delete_from_our_metadata_(3);
1877 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1878 return die_c_("during chain.write(true, false)", chain.status());
1879 if(!compare_chain_(chain, 0, 0))
1880 return false;
1881 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1882 return false;
1884 printf("SVPAP\tsort padding\n");
1885 chain.sort_padding();
1886 add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
1887 delete_from_our_metadata_(2);
1889 if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1890 return die_c_("during chain.write(true, false)", chain.status());
1891 if(!compare_chain_(chain, 0, 0))
1892 return false;
1893 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
1894 return false;
1896 printf("create iterator\n");
1898 FLAC::Metadata::Iterator iterator;
1899 if(!iterator.is_valid())
1900 return die_("allocating memory for iterator");
1902 our_current_position = 0;
1904 iterator.init(chain);
1906 printf("[S]VAP\tnext\n");
1907 if(!iterator.next())
1908 return die_("iterator ended early\n");
1909 our_current_position++;
1911 printf("S[V]AP\tnext\n");
1912 if(!iterator.next())
1913 return die_("iterator ended early\n");
1914 our_current_position++;
1916 printf("SV[A]P\tdelete middle block, replace with padding\n");
1917 if(0 == (padding = new FLAC::Metadata::Padding()))
1918 return die_("creating PADDING block");
1919 padding->set_length(71);
1920 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1921 return die_("copying object");
1922 if(!iterator.delete_block(/*replace_with_padding=*/true))
1923 return die_c_("iterator.delete_block(true)", chain.status());
1925 block = iterator.get_block();
1926 if(!compare_chain_(chain, our_current_position, block))
1927 return false;
1928 delete block;
1930 printf("S[V]PP\tnext\n");
1931 if(!iterator.next())
1932 return die_("iterator ended early\n");
1933 our_current_position++;
1935 printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1936 delete_from_our_metadata_(our_current_position--);
1937 if(!iterator.delete_block(/*replace_with_padding=*/false))
1938 return die_c_("iterator.delete_block(false)", chain.status());
1940 block = iterator.get_block();
1941 if(!compare_chain_(chain, our_current_position, block))
1942 return false;
1943 delete block;
1945 printf("S[V]P\tnext\n");
1946 if(!iterator.next())
1947 return die_("iterator ended early\n");
1948 our_current_position++;
1950 printf("SV[P]\tdelete last block, replace with padding\n");
1951 if(0 == (padding = new FLAC::Metadata::Padding()))
1952 return die_("creating PADDING block");
1953 padding->set_length(219);
1954 if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1955 return die_("copying object");
1956 if(!iterator.delete_block(/*replace_with_padding=*/true))
1957 return die_c_("iterator.delete_block(true)", chain.status());
1959 block = iterator.get_block();
1960 if(!compare_chain_(chain, our_current_position, block))
1961 return false;
1962 delete block;
1964 printf("S[V]P\tnext\n");
1965 if(!iterator.next())
1966 return die_("iterator ended early\n");
1967 our_current_position++;
1969 printf("SV[P]\tdelete last block, don't replace with padding\n");
1970 delete_from_our_metadata_(our_current_position--);
1971 if(!iterator.delete_block(/*replace_with_padding=*/false))
1972 return die_c_("iterator.delete_block(false)", chain.status());
1974 block = iterator.get_block();
1975 if(!compare_chain_(chain, our_current_position, block))
1976 return false;
1977 delete block;
1979 printf("S[V]\tprev\n");
1980 if(!iterator.prev())
1981 return die_("iterator ended early\n");
1982 our_current_position--;
1984 printf("[S]V\tdelete STREAMINFO block, should fail\n");
1985 if(iterator.delete_block(/*replace_with_padding=*/false))
1986 return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
1988 block = iterator.get_block();
1989 if(!compare_chain_(chain, our_current_position, block))
1990 return false;
1991 delete block;
1993 } // delete iterator
1994 our_current_position = 0;
1996 printf("SV\tmerge padding\n");
1997 chain.merge_padding();
1999 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
2000 return die_c_("during chain.write(false, false)", chain.status());
2001 if(!compare_chain_(chain, 0, 0))
2002 return false;
2003 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2004 return false;
2006 printf("SV\tsort padding\n");
2007 chain.sort_padding();
2009 if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
2010 return die_c_("during chain.write(false, false)", chain.status());
2011 if(!compare_chain_(chain, 0, 0))
2012 return false;
2013 if(!test_file_(is_ogg, /*ignore_metadata=*/false))
2014 return false;
2016 end:
2017 if(!remove_file_(flacfilename(is_ogg)))
2018 return false;
2020 return true;
2023 static bool test_level_2_misc_(bool is_ogg)
2025 ::FLAC__IOCallbacks callbacks;
2027 memset(&callbacks, 0, sizeof(callbacks));
2028 callbacks.read = (::FLAC__IOCallback_Read)fread;
2029 #ifdef FLAC__VALGRIND_TESTING
2030 callbacks.write = chain_write_cb_;
2031 #else
2032 callbacks.write = (::FLAC__IOCallback_Write)fwrite;
2033 #endif
2034 callbacks.seek = chain_seek_cb_;
2035 callbacks.tell = chain_tell_cb_;
2036 callbacks.eof = chain_eof_cb_;
2038 printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
2040 printf("generate file\n");
2042 if(!generate_file_(/*include_extras=*/false, is_ogg))
2043 return false;
2045 printf("create chain\n");
2046 FLAC::Metadata::Chain chain;
2047 if(!chain.is_valid())
2048 return die_("allocating chain");
2050 printf("read chain (filename-based)\n");
2052 if(!chain.read(flacfilename(is_ogg)))
2053 return die_c_("reading chain", chain.status());
2055 printf("write chain with wrong method Chain::write(with callbacks)\n");
2057 if(chain.write(/*use_padding=*/false, 0, callbacks))
2058 return die_c_("mismatched write should have failed", chain.status());
2059 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2060 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2061 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2064 printf("read chain (filename-based)\n");
2066 if(!chain.read(flacfilename(is_ogg)))
2067 return die_c_("reading chain", chain.status());
2069 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2071 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2072 return die_c_("mismatched write should have failed", chain.status());
2073 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2074 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2075 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2078 printf("read chain (callback-based)\n");
2080 FILE *file = fopen(flacfilename(is_ogg), "rb");
2081 if(0 == file)
2082 return die_("opening file");
2083 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2084 fclose(file);
2085 return die_c_("reading chain", chain.status());
2087 fclose(file);
2090 printf("write chain with wrong method write()\n");
2092 if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
2093 return die_c_("mismatched write should have failed", chain.status());
2094 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2095 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
2096 printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2099 printf("read chain (callback-based)\n");
2101 FILE *file = fopen(flacfilename(is_ogg), "rb");
2102 if(0 == file)
2103 return die_("opening file");
2104 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2105 fclose(file);
2106 return die_c_("reading chain", chain.status());
2108 fclose(file);
2111 printf("testing Chain::check_if_tempfile_needed()... ");
2113 if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
2114 printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
2115 else
2116 return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
2118 printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
2120 if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
2121 return die_c_("mismatched write should have failed", chain.status());
2122 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2123 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2124 printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2127 printf("read chain (callback-based)\n");
2129 FILE *file = fopen(flacfilename(is_ogg), "rb");
2130 if(0 == file)
2131 return die_("opening file");
2132 if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
2133 fclose(file);
2134 return die_c_("reading chain", chain.status());
2136 fclose(file);
2139 printf("create iterator\n");
2141 FLAC::Metadata::Iterator iterator;
2142 if(!iterator.is_valid())
2143 return die_("allocating memory for iterator");
2145 iterator.init(chain);
2147 printf("[S]VP\tnext\n");
2148 if(!iterator.next())
2149 return die_("iterator ended early\n");
2151 printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2152 if(!iterator.delete_block(/*replace_with_padding=*/false))
2153 return die_c_("block delete failed\n", chain.status());
2155 printf("testing Chain::check_if_tempfile_needed()... ");
2157 if(chain.check_if_tempfile_needed(/*use_padding=*/false))
2158 printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
2159 else
2160 return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
2162 printf("write chain with wrong method Chain::write(with callbacks)\n");
2164 if(chain.write(/*use_padding=*/false, 0, callbacks))
2165 return die_c_("mismatched write should have failed", chain.status());
2166 if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2167 return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
2168 printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2171 } // delete iterator
2173 if(!remove_file_(flacfilename(is_ogg)))
2174 return false;
2176 return true;
2179 bool test_metadata_file_manipulation()
2181 printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n");
2183 our_metadata_.num_blocks = 0;
2185 if(!test_level_0_())
2186 return false;
2188 if(!test_level_1_())
2189 return false;
2191 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2192 return false;
2193 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2194 return false;
2195 if(!test_level_2_misc_(/*is_ogg=*/false))
2196 return false;
2198 if(FLAC_API_SUPPORTS_OGG_FLAC) {
2199 if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2200 return false;
2201 if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2202 return false;
2203 #if 0
2204 /* when ogg flac write is supported, will have to add this: */
2205 if(!test_level_2_misc_(/*is_ogg=*/true))
2206 return false;
2207 #endif
2210 return true;