diff options
Diffstat (limited to '3rdparty/flac/src/test_libFLAC/decoders.c')
-rw-r--r-- | 3rdparty/flac/src/test_libFLAC/decoders.c | 1054 |
1 files changed, 1054 insertions, 0 deletions
diff --git a/3rdparty/flac/src/test_libFLAC/decoders.c b/3rdparty/flac/src/test_libFLAC/decoders.c new file mode 100644 index 00000000000..ae114ceda87 --- /dev/null +++ b/3rdparty/flac/src/test_libFLAC/decoders.c @@ -0,0 +1,1054 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "decoders.h" +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "share/safe_str.h" +#include "test_libs_common/file_utils_flac.h" +#include "test_libs_common/metadata_utils.h" + +typedef enum { + LAYER_STREAM = 0, /* FLAC__stream_decoder_init_[ogg_]stream() without seeking */ + LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_[ogg_]stream() with seeking */ + LAYER_FILE, /* FLAC__stream_decoder_init_[ogg_]FILE() */ + LAYER_FILENAME /* FLAC__stream_decoder_init_[ogg_]file() */ +} Layer; + +static const char * const LayerString[] = { + "Stream", + "Seekable Stream", + "FILE*", + "Filename" +}; + +typedef struct { + Layer layer; + FILE *file; + char filename[512]; + uint32_t current_metadata_number; + FLAC__bool ignore_errors; + FLAC__bool error_occurred; +} StreamDecoderClientData; + +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *expected_metadata_sequence_[9]; +static uint32_t num_expected_; +static FLAC__off_t flacfilesize_; + +static const char *flacfilename(FLAC__bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static FLAC__bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder) +{ + FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); + + if(msg) + printf("FAILED, %s", msg); + else + printf("FAILED"); + + printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamDecoderStateString[state]); + + return false; +} + +static void open_test_file(StreamDecoderClientData * pdcd, int is_ogg, const char * mode) +{ + pdcd->file = flac_fopen(flacfilename(is_ogg), mode); + safe_strncpy(pdcd->filename, flacfilename(is_ogg), sizeof (pdcd->filename)); +} + +static void init_metadata_blocks_(void) +{ + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static void free_metadata_blocks_(void) +{ + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static FLAC__bool generate_file_(FLAC__bool is_ogg) +{ + printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":""); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */ + + if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_)) + return die_("creating the encoded file"); + + return true; +} + +static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + const size_t requested_bytes = *bytes; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in read callback is NULL\n"); + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + + if(feof(dcd->file)) { + *bytes = 0; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + else if(requested_bytes > 0) { + *bytes = fread(buffer, 1, requested_bytes, dcd->file); + if(*bytes == 0) { + if(feof(dcd->file)) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + else { + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ +} + +static FLAC__StreamDecoderSeekStatus stream_decoder_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in seek callback is NULL\n"); + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + + if(fseeko(dcd->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) { + dcd->error_occurred = true; + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +static FLAC__StreamDecoderTellStatus stream_decoder_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + FLAC__off_t offset; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in tell callback is NULL\n"); + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + + offset = ftello(dcd->file); + *absolute_byte_offset = (FLAC__uint64)offset; + + if(offset < 0) { + dcd->error_occurred = true; + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + + return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + +static FLAC__StreamDecoderLengthStatus stream_decoder_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in length callback is NULL\n"); + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + + *stream_length = (FLAC__uint64)flacfilesize_; + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} + +static FLAC__bool stream_decoder_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in eof callback is NULL\n"); + return true; + } + + if(dcd->error_occurred) + return true; + + return feof(dcd->file); +} + +static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder, (void)buffer; + + if(0 == dcd) { + printf("ERROR: client_data in write callback is NULL\n"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + if( + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) || + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0) + ) { + printf("content... "); + fflush(stdout); + } + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in metadata callback is NULL\n"); + return; + } + + if(dcd->error_occurred) + return; + + if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) { + printf ("%u ('%c%c%c%c')... ", dcd->current_metadata_number, metadata->data.application.id [0], metadata->data.application.id [1], metadata->data.application.id [2], metadata->data.application.id [3]); + } + else { + printf("%u... ", dcd->current_metadata_number); + } + fflush(stdout); + + + if(dcd->current_metadata_number >= num_expected_) { + (void)die_("got more metadata blocks than expected"); + dcd->error_occurred = true; + } + else { + if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) { + (void)die_("metadata block mismatch"); + dcd->error_occurred = true; + } + } + dcd->current_metadata_number++; +} + +static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in error callback is NULL\n"); + return; + } + + if(!dcd->ignore_errors) { + printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, FLAC__StreamDecoderErrorStatusString[status]); + dcd->error_occurred = true; + } +} + +static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg) +{ + FLAC__StreamDecoderInitStatus init_status; + + if(!FLAC__stream_decoder_set_md5_checking(decoder, true)) + return die_s_("at FLAC__stream_decoder_set_md5_checking(), returned false", decoder); + + /* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */ + if(dcd->layer == LAYER_FILE) { + printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); + open_test_file(dcd, is_ogg, "rb"); + if(0 == dcd->file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + } + + switch(dcd->layer) { + case LAYER_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) + ; + break; + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd); + break; + case LAYER_FILE: + printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd); + break; + default: + die_("internal error 000"); + return false; + } + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, decoder); + printf("OK\n"); + + dcd->current_metadata_number = 0; + + if(dcd->layer < LAYER_FILE && fseeko(dcd->file, 0, SEEK_SET) < 0) { + printf("FAILED rewinding input, errno = %d\n", errno); + return false; + } + + printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_finish()... "); + if(!FLAC__stream_decoder_finish(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + return true; +} + +static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg) +{ + FLAC__StreamDecoder *decoder; + FLAC__StreamDecoderInitStatus init_status; + FLAC__StreamDecoderState state; + StreamDecoderClientData decoder_client_data; + FLAC__bool expect; + + decoder_client_data.layer = layer; + + printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC"); + + printf("testing FLAC__stream_decoder_new()... "); + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_delete()... "); + FLAC__stream_decoder_delete(decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_new()... "); + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + switch(layer) { + case LAYER_STREAM: + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) : + FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case LAYER_FILE: + printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) : + FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) : + FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0); + break; + default: + die_("internal error 003"); + return false; + } + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS) + return die_s_(0, decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_delete()... "); + FLAC__stream_decoder_delete(decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + + printf("testing FLAC__stream_decoder_new()... "); + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + if(is_ogg) { + printf("testing FLAC__stream_decoder_set_ogg_serial_number()... "); + if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number)) + return die_s_("returned false", decoder); + printf("OK\n"); + } + + printf("testing FLAC__stream_decoder_set_md5_checking()... "); + if(!FLAC__stream_decoder_set_md5_checking(decoder, true)) + return die_s_("returned false", decoder); + printf("OK\n"); + + if(layer < LAYER_FILENAME) { + printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); + open_test_file(&decoder_client_data, is_ogg, "rb"); + if(0 == decoder_client_data.file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + } + + switch(layer) { + case LAYER_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + case LAYER_FILE: + printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + default: + die_("internal error 009"); + return false; + } + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_state()... "); + state = FLAC__stream_decoder_get_state(decoder); + printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]); + + decoder_client_data.current_metadata_number = 0; + decoder_client_data.ignore_errors = false; + decoder_client_data.error_occurred = false; + + printf("testing FLAC__stream_decoder_get_md5_checking()... "); + if(!FLAC__stream_decoder_get_md5_checking(decoder)) { + printf("FAILED, returned false, expected true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... "); + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_process_single()... "); + if(!FLAC__stream_decoder_process_single(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_skip_single_frame()... "); + if(!FLAC__stream_decoder_skip_single_frame(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + if(layer < LAYER_FILE) { + printf("testing FLAC__stream_decoder_flush()... "); + if(!FLAC__stream_decoder_flush(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + decoder_client_data.ignore_errors = true; + printf("testing FLAC__stream_decoder_process_single()... "); + if(!FLAC__stream_decoder_process_single(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + decoder_client_data.ignore_errors = false; + } + + expect = (layer != LAYER_STREAM); + printf("testing FLAC__stream_decoder_seek_absolute()... "); + if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) + return die_s_(expect? "returned false" : "returned true", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + expect = (layer != LAYER_STREAM); + printf("testing FLAC__stream_decoder_seek_absolute()... "); + if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) + return die_s_(expect? "returned false" : "returned true", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_channels()... "); + { + uint32_t channels = FLAC__stream_decoder_get_channels(decoder); + if(channels != streaminfo_.data.stream_info.channels) { + printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels); + return false; + } + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_bits_per_sample()... "); + { + uint32_t bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder); + if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) { + printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample); + return false; + } + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_sample_rate()... "); + { + uint32_t sample_rate = FLAC__stream_decoder_get_sample_rate(decoder); + if(sample_rate != streaminfo_.data.stream_info.sample_rate) { + printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate); + return false; + } + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_blocksize()... "); + { + uint32_t blocksize = FLAC__stream_decoder_get_blocksize(decoder); + /* value could be anything since we're at the last block, so accept any reasonable answer */ + printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED"); + if(blocksize == 0) + return false; + } + + printf("testing FLAC__stream_decoder_get_channel_assignment()... "); + { + FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder); + printf("returned %u (%s)... OK\n", (uint32_t)ca, FLAC__ChannelAssignmentString[ca]); + } + + if(layer < LAYER_FILE) { + printf("testing FLAC__stream_decoder_reset()... "); + if(!FLAC__stream_decoder_reset(decoder)) { + state = FLAC__stream_decoder_get_state(decoder); + printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]); + return false; + } + printf("OK\n"); + + if(layer == LAYER_STREAM) { + /* after a reset() we have to rewind the input ourselves */ + printf("rewinding input... "); + if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) { + printf("FAILED, errno = %d\n", errno); + return false; + } + printf("OK\n"); + } + + decoder_client_data.current_metadata_number = 0; + + printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + } + + printf("testing FLAC__stream_decoder_finish()... "); + if(!FLAC__stream_decoder_finish(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + /* + * respond all + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore VORBIS_COMMENT + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... "); + if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + if(!is_ogg) /* encoder removes seektable for ogg */ + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION id of app#1 & app#2 + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond VORBIS_COMMENT + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... "); + if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION id of app#1 & app#2 + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION, respond APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION, ignore APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */ + fclose(decoder_client_data.file); + + printf("testing FLAC__stream_decoder_delete()... "); + FLAC__stream_decoder_delete(decoder); + printf("OK\n"); + + printf("\nPASSED!\n"); + + return true; +} + +FLAC__bool test_decoders(void) +{ + FLAC__bool is_ogg = false; + + while(1) { + init_metadata_blocks_(); + + if(!generate_file_(is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_STREAM, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_FILE, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_FILENAME, is_ogg)) + return false; + + (void) grabbag__file_remove_file(flacfilename(is_ogg)); + + free_metadata_blocks_(); + + if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg) + break; + is_ogg = true; + } + + return true; +} |