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