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:
OurFileDecoder(bool ignore_metadata)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
flacfilename(bool is_ogg)82 static const char *flacfilename(bool is_ogg)
83 {
84 return is_ogg? "metadata.oga" : "metadata.flac";
85 }
86
die_(const char * msg)87 static bool die_(const char *msg)
88 {
89 printf("ERROR: %s\n", msg);
90 return false;
91 }
92
die_c_(const char * msg,FLAC::Metadata::Chain::Status status)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
die_ss_(const char * msg,FLAC::Metadata::SimpleIterator & iterator)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
malloc_or_die_(size_t size)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
strdup_or_die_(const char * s)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
replace_in_our_metadata_(FLAC::Metadata::Prototype * block,unsigned position,bool copy)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
insert_to_our_metadata_(FLAC::Metadata::Prototype * block,unsigned position,bool copy)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
delete_from_our_metadata_(unsigned position)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
add_to_padding_length_(unsigned indx,int delta)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 */
open_tempfile_(const char * filename,FILE ** tempfile,char ** tempfilename)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
cleanup_tempfile_(FILE ** tempfile,char ** tempfilename)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
transport_tempfile_(const char * filename,FILE ** tempfile,char ** tempfilename)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
get_file_stats_(const char * filename,struct flac_stat_s * stats)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
set_file_stats_(const char * filename,struct flac_stat_s * stats)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
chain_write_cb_(const void * ptr,size_t size,size_t nmemb,::FLAC__IOHandle handle)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
chain_seek_cb_(::FLAC__IOHandle handle,FLAC__int64 offset,int whence)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
chain_tell_cb_(::FLAC__IOHandle handle)305 static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
306 {
307 return ftello((FILE*)handle);
308 }
309
chain_eof_cb_(::FLAC__IOHandle handle)310 static int chain_eof_cb_(::FLAC__IOHandle handle)
311 {
312 return feof((FILE*)handle);
313 }
314
write_chain_(FLAC::Metadata::Chain & chain,bool use_padding,bool preserve_file_stats,bool filename_based,const char * filename)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
read_chain_(FLAC::Metadata::Chain & chain,const char * filename,bool filename_based,bool is_ogg)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
compare_chain_(FLAC::Metadata::Chain & chain,unsigned current_position,FLAC::Metadata::Prototype * current_block)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
write_callback(const::FLAC__Frame * frame,const FLAC__int32 * const buffer[])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
metadata_callback(const::FLAC__StreamMetadata * metadata)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
error_callback(::FLAC__StreamDecoderErrorStatus status)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
generate_file_(bool include_extras,bool is_ogg)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
test_file_(bool is_ogg,bool ignore_metadata)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
change_stats_(const char * filename,bool read_only)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
remove_file_(const char * filename)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
test_level_0_()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
test_level_1_()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
test_level_2_(bool filename_based,bool is_ogg)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
test_level_2_misc_(bool is_ogg)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
test_metadata_file_manipulation()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