finish stream/seekable_stream/file decoder tests
authorJosh Coalson <jcoalson@users.sourceforce.net>
Tue, 4 Jun 2002 05:41:39 +0000 (05:41 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Tue, 4 Jun 2002 05:41:39 +0000 (05:41 +0000)
src/test_unit/decoders.c

index 21a3c8f..b11a21a 100644 (file)
@@ -23,6 +23,7 @@
 #include "FLAC/file_decoder.h"
 #include "FLAC/seekable_stream_decoder.h"
 #include "FLAC/stream_decoder.h"
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 typedef struct {
        FILE *file;
        unsigned current_metadata_number;
+       FLAC__bool ignore_errors;
        FLAC__bool error_occurred;
 } stream_decoder_client_data_struct;
 
+typedef stream_decoder_client_data_struct seekable_stream_decoder_client_data_struct;
+typedef stream_decoder_client_data_struct file_decoder_client_data_struct;
+
 static FLAC__StreamMetaData streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_;
 static FLAC__StreamMetaData *expected_metadata_sequence_[6];
 static unsigned num_expected_;
 static const char *flacfilename_ = "metadata.flac";
+static unsigned flacfilesize_;
 
 static FLAC__bool die_(const char *msg)
 {
@@ -142,13 +148,13 @@ static FLAC__bool generate_file_()
        expected_metadata_sequence_[4] = &vorbiscomment_;
        num_expected_ = 5;
 
-       if(!file_utils__generate_flacfile(flacfilename_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+       if(!file_utils__generate_flacfile(flacfilename_, &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
                return die_("creating the encoded file"); 
 
        return true;
 }
 
-FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
 {
        stream_decoder_client_data_struct *dcd = (stream_decoder_client_data_struct*)client_data;
 
@@ -156,32 +162,32 @@ FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDe
 
        if(0 == dcd) {
                printf("ERROR: client_data in read callback is NULL\n");
-               return FLAC__STREAM_DECODER_READ_ABORT;
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
        }
 
        if(dcd->error_occurred)
-               return FLAC__STREAM_DECODER_READ_ABORT;
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
 
        if(feof(dcd->file))
-               return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
+               return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
     else if(*bytes > 0) {
         unsigned bytes_read = fread(buffer, 1, *bytes, dcd->file);
         if(bytes_read == 0) {
             if(feof(dcd->file))
-                return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
+                return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
             else
-                return FLAC__STREAM_DECODER_READ_CONTINUE;
+                return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
         }
         else {
             *bytes = bytes_read;
-            return FLAC__STREAM_DECODER_READ_CONTINUE;
+            return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
         }
     }
     else
-        return FLAC__STREAM_DECODER_READ_ABORT; /* abort to avoid a deadlock */
+        return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
 }
 
-FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
 {
        stream_decoder_client_data_struct *dcd = (stream_decoder_client_data_struct*)client_data;
 
@@ -189,11 +195,11 @@ FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__Stream
 
        if(0 == dcd) {
                printf("ERROR: client_data in write callback is NULL\n");
-               return FLAC__STREAM_DECODER_WRITE_ABORT;
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
        }
 
        if(dcd->error_occurred)
-               return FLAC__STREAM_DECODER_WRITE_ABORT;
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 
     if(
         (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
@@ -203,10 +209,10 @@ FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__Stream
         fflush(stdout);
     }
 
-       return FLAC__STREAM_DECODER_WRITE_CONTINUE;
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 }
 
-void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
 {
        stream_decoder_client_data_struct *dcd = (stream_decoder_client_data_struct*)client_data;
 
@@ -236,20 +242,81 @@ void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const
        dcd->current_metadata_number++;
 }
 
-void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
        stream_decoder_client_data_struct *dcd = (stream_decoder_client_data_struct*)client_data;
 
        (void)decoder;
 
-       printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, FLAC__StreamDecoderErrorStatusString[status]);
-
        if(0 == dcd) {
                printf("ERROR: client_data in error callback is NULL\n");
                return;
        }
 
-       dcd->error_occurred = true;
+       if(!dcd->ignore_errors) {
+               printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, FLAC__StreamDecoderErrorStatusString[status]);
+               dcd->error_occurred = true;
+       }
+}
+
+static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, stream_decoder_client_data_struct *dcd)
+{
+       FLAC__StreamDecoderState state;
+
+       if(!FLAC__stream_decoder_set_read_callback(decoder, stream_decoder_read_callback_)) {
+               printf("FAILED at FLAC__stream_decoder_set_read_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__stream_decoder_set_write_callback(decoder, stream_decoder_write_callback_)) {
+               printf("FAILED at FLAC__stream_decoder_set_write_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__stream_decoder_set_metadata_callback(decoder, stream_decoder_metadata_callback_)) {
+               printf("FAILED at FLAC__stream_decoder_set_metadata_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__stream_decoder_set_error_callback(decoder, stream_decoder_error_callback_)) {
+               printf("FAILED at FLAC__stream_decoder_set_error_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__stream_decoder_set_client_data(decoder, dcd)) {
+               printf("FAILED at FLAC__stream_decoder_set_client_data(), returned false\n");
+               return false;
+       }
+
+       printf("testing FLAC__stream_decoder_init()... ");
+       if((state = FLAC__stream_decoder_init(decoder)) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) {
+               printf("FAILED, returned state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       dcd->current_metadata_number = 0;
+
+       printf("rewinding input... ");
+       if(fseek(dcd->file, 0, SEEK_SET) < 0) {
+               printf("FAILED, errno = %d\n", errno);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_process_whole_stream()... ");
+       if(!FLAC__stream_decoder_process_whole_stream(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");
+
+       printf("testing FLAC__stream_decoder_finish()... ");
+       FLAC__stream_decoder_finish(decoder);
+       printf("OK\n");
+
+       return true;;
 }
 
 FLAC__bool test_stream_decoder()
@@ -313,7 +380,12 @@ FLAC__bool test_stream_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("opening FLAC file... ");
@@ -340,6 +412,24 @@ FLAC__bool test_stream_decoder()
        }
        printf("OK\n");
 
+       printf("testing FLAC__stream_decoder_flush()... ");
+       if(!FLAC__stream_decoder_flush(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");
+
+       decoder_client_data.ignore_errors = true;
+       printf("testing FLAC__stream_decoder_process_one_frame()... ");
+       if(!FLAC__stream_decoder_process_one_frame(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");
+       decoder_client_data.ignore_errors = false;
+
        printf("testing FLAC__stream_decoder_process_remaining_frames()... ");
        if(!FLAC__stream_decoder_process_remaining_frames(decoder)) {
                state = FLAC__stream_decoder_get_state(decoder);
@@ -348,10 +438,88 @@ FLAC__bool test_stream_decoder()
        }
        printf("OK\n");
 
+       printf("testing FLAC__stream_decoder_get_channels()... ");
+       {
+               unsigned 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()... ");
+       {
+               unsigned 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()... ");
+       {
+               unsigned 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()... ");
+       {
+               unsigned blocksize = FLAC__stream_decoder_get_blocksize(decoder);
+               /* value could be anything since we're at the last block, so accept any answer */
+               printf("returned %u... OK\n", blocksize);
+       }
+
+       printf("testing FLAC__stream_decoder_get_channel_assignment()... ");
+       {
+               FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder);
+               printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+       }
+
+       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");
+
+       decoder_client_data.current_metadata_number = 0;
+
+       printf("rewinding input... ");
+       if(fseek(decoder_client_data.file, 0, SEEK_SET) < 0) {
+               printf("FAILED, errno = %d\n", errno);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_process_whole_stream()... ");
+       if(!FLAC__stream_decoder_process_whole_stream(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");
+
        printf("testing FLAC__stream_decoder_finish()... ");
        FLAC__stream_decoder_finish(decoder);
        printf("OK\n");
 
+       /*
+        * respond all
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
        num_expected_ = 0;
        expected_metadata_sequence_[num_expected_++] = &streaminfo_;
@@ -361,187 +529,1742 @@ FLAC__bool test_stream_decoder()
        expected_metadata_sequence_[num_expected_++] = &application2_;
        expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 
-       printf("testing FLAC__stream_decoder_delete()... ");
-       FLAC__stream_decoder_delete(decoder);
-       printf("OK\n");
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
 
-       printf("\nPASSED!\n");
+       /*
+        * ignore all
+        */
 
-       return true;
-}
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-FLAC__bool test_seekable_stream_decoder()
-{
-       printf("\n+++ unit test: FLAC__SeekableStreamDecoder\n\n");
+       num_expected_ = 0;
 
-       printf("\nPASSED!\n");
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
 
-       return true;
-}
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
 
-FLAC__bool test_file_decoder()
-{
-       printf("\n+++ unit test: FLAC__FileDecoder\n\n");
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-       printf("\nPASSED!\n");
+       printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-       return true;
-}
+       num_expected_ = 0;
+       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_;
 
-int test_decoders()
-{
-       init_metadata_blocks_();
-       if(!generate_file_())
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
                return 1;
 
-       if(!test_stream_decoder())
-               return 1;
+       /*
+        * respond all, ignore APPLICATION
+        */
 
-       if(!test_seekable_stream_decoder())
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
                return 1;
 
-       if(!test_file_decoder())
+       /*
+        * 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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
                return 1;
 
-       (void) file_utils__remove_file(flacfilename_);
-       free_metadata_blocks_();
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
 
-       return 0;
-}
-#if 0
-extern const char *FLAC__StreamDecoderStateString[];
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-typedef enum {
-       FLAC__STREAM_DECODER_READ_CONTINUE,
-       FLAC__STREAM_DECODER_READ_END_OF_STREAM,
-       FLAC__STREAM_DECODER_READ_ABORT
-} FLAC__StreamDecoderReadStatus;
-extern const char *FLAC__StreamDecoderReadStatusString[];
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-typedef enum {
-       FLAC__STREAM_DECODER_WRITE_CONTINUE,
-       FLAC__STREAM_DECODER_WRITE_ABORT
-} FLAC__StreamDecoderWriteStatus;
-extern const char *FLAC__StreamDecoderWriteStatusString[];
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-typedef enum {
-       FLAC__STREAM_DECODER_ERROR_LOST_SYNC,
-       FLAC__STREAM_DECODER_ERROR_BAD_HEADER,
-       FLAC__STREAM_DECODER_ERROR_FRAME_CRC_MISMATCH
-} FLAC__StreamDecoderErrorStatus;
-extern const char *FLAC__StreamDecoderErrorStatusString[];
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
 
-/*
- * Any parameters that are not set before FLAC__stream_decoder_init()
- * will take on the defaults from the constructor, shown below.
- * For more on what the parameters mean, see the documentation.
- *
- *        (*read_callback)()               (DEFAULT: NULL ) The callbacks are the only values that MUST be set before FLAC__stream_decoder_init()
- *        (*write_callback)()              (DEFAULT: NULL )
- *        (*metadata_callback)()           (DEFAULT: NULL )
- *        (*error_callback)()              (DEFAULT: NULL )
- * void*    client_data                    (DEFAULT: NULL ) passed back through the callbacks
- */
-FLAC__StreamDecoder *FLAC__stream_decoder_new();
-void FLAC__stream_decoder_delete(FLAC__StreamDecoder *);
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
 
-/***********************************************************************
- *
- * Public class method prototypes
- *
- ***********************************************************************/
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-/*
- * Various "set" methods.  These may only be called when the decoder
- * is in the state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after
- * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but
- * before FLAC__stream_decoder_init().  If this is the case they will
- * return true, otherwise false.
- *
- * NOTE that these functions do not validate the values as many are
- * interdependent.  The FLAC__stream_decoder_init() function will do
- * this, so make sure to pay attention to the state returned by
- * FLAC__stream_decoder_init().
- *
- * Any parameters that are not set before FLAC__stream_decoder_init()
- * will take on the defaults from the constructor.  NOTE that
- * FLAC__stream_decoder_flush() or FLAC__stream_decoder_reset() do
- * NOT reset the values to the constructor defaults.
-@@@@ update so that only _set_ methods that need to return FLAC__bool, else void; update documentation.html also
-@@@@ update defaults above and in documentation.html about the metadata_respond/ignore defaults
- */
-FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadStatus (*value)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data));
-FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data));
-FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, void (*value)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data));
-FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, void (*value)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data));
-FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value);
-/*
- * These deserve special attention.  By default, the decoder only calls the
- * metadata_callback for the STREAMINFO block.  These functions allow you to
- * tell the decoder explicitly which blocks to parse and return via the
- * metadata_callback and/or which to skip.  Use a _respond_all(), _ignore() ...
- * or _ignore_all(), _respond() ... sequence to exactly specify which blocks
- * to return.  Remember that some metadata blocks can be big so filtering out
- * the ones you don't use can reduce the memory requirements of the decoder.
- * Also note the special forms _respond/_ignore_application(id) for filtering
- * APPLICATION blocks based on the application ID.
- *
- * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but
- * they still can legally be filtered from the metadata_callback here.
- */
-FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetaDataType type);
-FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
-FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder);
-FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetaDataType type);
-FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
-FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder);
+       printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
 
-/*
- * Methods to return the current stream decoder state, number
- * of channels, channel assignment, bits-per-sample, sample
- * rate in Hz, and blocksize in samples.  All but the decoder
- * state will only be valid after decoding has started.
- */
-FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder);
-unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
-FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder);
-unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
-unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
-unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 
-/*
- * Initialize the instance; should be called after construction and
- * 'set' calls but before any of the 'process' calls.  Will set and
- * return the decoder state, which will be
- * FLAC__STREAM_DECODER_SEARCH_FOR_METADATA if initialization
- * succeeded.
- */
-FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder);
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
 
-/*
- * Flush the decoding buffer, release resources, and return the decoder
- * state to FLAC__STREAM_DECODER_UNINITIALIZED.
- */
-void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+       /*
+        * ignore all, respond APPLICATION
+        */
 
-/*
- * state control methods
- */
-FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
-FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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))
+               return 1;
+
+       /*
+        * 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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * 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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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))
+               return 1;
+
+       /*
+        * 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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * 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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       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)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /* done, now leave the sequence the way we found it... */
+       num_expected_ = 0;
+       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_;
+
+       printf("testing FLAC__stream_decoder_delete()... ");
+       FLAC__stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       fclose(decoder_client_data.file);
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+static FLAC__SeekableStreamDecoderReadStatus seekable_stream_decoder_read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+       (void)decoder;
+       switch(stream_decoder_read_callback_(0, buffer, bytes, client_data)) {
+               case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE:
+                       return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
+               case FLAC__STREAM_DECODER_READ_STATUS_ABORT:
+               case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM:
+                       return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
+               default:
+                       FLAC__ASSERT(0);
+                       return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
+       }
+}
+
+static FLAC__SeekableStreamDecoderSeekStatus seekable_stream_decoder_seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       seekable_stream_decoder_client_data_struct *dcd = (seekable_stream_decoder_client_data_struct*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in seek callback is NULL\n");
+               return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+
+       if(fseek(dcd->file, absolute_byte_offset, SEEK_SET) < 0) {
+               dcd->error_occurred = true;
+               return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+       }
+
+       return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__SeekableStreamDecoderTellStatus seekable_stream_decoder_tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       seekable_stream_decoder_client_data_struct *dcd = (seekable_stream_decoder_client_data_struct*)client_data;
+       long offset;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in tell callback is NULL\n");
+               return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+
+       offset = ftell(dcd->file);
+       *absolute_byte_offset = (FLAC__uint64)offset;
+
+       if(offset < 0) {
+               dcd->error_occurred = true;
+               return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+       }
+
+       return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__SeekableStreamDecoderLengthStatus seekable_stream_decoder_length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+       seekable_stream_decoder_client_data_struct *dcd = (seekable_stream_decoder_client_data_struct*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in length callback is NULL\n");
+               return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+       *stream_length = (FLAC__uint64)flacfilesize_;
+       return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool seekable_stream_decoder_eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data)
+{
+       seekable_stream_decoder_client_data_struct *dcd = (seekable_stream_decoder_client_data_struct*)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 seekable_stream_decoder_write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+{
+       (void)decoder;
+       return stream_decoder_write_callback_(0, frame, buffer, client_data);
+}
+
+static void seekable_stream_decoder_metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+       (void)decoder;
+       stream_decoder_metadata_callback_(0, metadata, client_data);
+}
+
+static void seekable_stream_decoder_error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       (void)decoder;
+       stream_decoder_error_callback_(0, status, client_data);
+}
+
+static FLAC__bool seekable_stream_decoder_test_respond_(FLAC__SeekableStreamDecoder *decoder, seekable_stream_decoder_client_data_struct *dcd)
+{
+       FLAC__SeekableStreamDecoderState state;
+
+       if(!FLAC__seekable_stream_decoder_set_read_callback(decoder, seekable_stream_decoder_read_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_read_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_seek_callback(decoder, seekable_stream_decoder_seek_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_seek_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_tell_callback(decoder, seekable_stream_decoder_tell_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_tell_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_length_callback(decoder, seekable_stream_decoder_length_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_length_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_eof_callback(decoder, seekable_stream_decoder_eof_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_eof_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_write_callback(decoder, seekable_stream_decoder_write_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_write_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_metadata_callback(decoder, seekable_stream_decoder_metadata_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_metadata_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_error_callback(decoder, seekable_stream_decoder_error_callback_)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_error_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_client_data(decoder, dcd)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_client_data(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__seekable_stream_decoder_set_md5_checking(decoder, true)) {
+               printf("FAILED at FLAC__seekable_stream_decoder_set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       printf("testing FLAC__seekable_stream_decoder_init()... ");
+       if((state = FLAC__seekable_stream_decoder_init(decoder)) != FLAC__SEEKABLE_STREAM_DECODER_OK) {
+               printf("FAILED, returned state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       dcd->current_metadata_number = 0;
+
+       if(fseek(dcd->file, 0, SEEK_SET) < 0) {
+               printf("FAILED rewinding input, errno = %d\n", errno);
+               return false;
+       }
+
+       printf("testing FLAC__seekable_stream_decoder_process_whole_stream()... ");
+       if(!FLAC__seekable_stream_decoder_process_whole_stream(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_finish()... ");
+       (void) FLAC__seekable_stream_decoder_finish(decoder);
+       printf("OK\n");
+
+       return true;;
+}
+
+FLAC__bool test_seekable_stream_decoder()
+{
+       FLAC__SeekableStreamDecoder *decoder;
+       FLAC__SeekableStreamDecoderState state;
+       seekable_stream_decoder_client_data_struct decoder_client_data;
+
+       printf("\n+++ unit test: FLAC__SeekableStreamDecoder\n\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("testing FLAC__seekable_stream_decoder_new()... ");
+       decoder = FLAC__seekable_stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_read_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_read_callback(decoder, seekable_stream_decoder_read_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_seek_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_seek_callback(decoder, seekable_stream_decoder_seek_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_tell_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_tell_callback(decoder, seekable_stream_decoder_tell_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_length_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_length_callback(decoder, seekable_stream_decoder_length_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_eof_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_eof_callback(decoder, seekable_stream_decoder_eof_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_write_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_write_callback(decoder, seekable_stream_decoder_write_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_callback(decoder, seekable_stream_decoder_metadata_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_error_callback()... ");
+       if(!FLAC__seekable_stream_decoder_set_error_callback(decoder, seekable_stream_decoder_error_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_client_data()... ");
+       if(!FLAC__seekable_stream_decoder_set_client_data(decoder, &decoder_client_data)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_md5_checking()... ");
+       if(!FLAC__seekable_stream_decoder_set_md5_checking(decoder, true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_init()... ");
+       if((state = FLAC__seekable_stream_decoder_init(decoder)) != FLAC__SEEKABLE_STREAM_DECODER_OK) {
+               printf("FAILED, returned state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_get_state()... ");
+       state = FLAC__seekable_stream_decoder_get_state(decoder);
+       printf("returned state = %u (%s)... OK\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+
+       decoder_client_data.current_metadata_number = 0;
+       decoder_client_data.ignore_errors = false;
+       decoder_client_data.error_occurred = false;
+
+       printf("opening FLAC file... ");
+       decoder_client_data.file = fopen(flacfilename_, "rb");
+       if(0 == decoder_client_data.file) {
+               printf("ERROR\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_get_md5_checking()... ");
+       if(!FLAC__seekable_stream_decoder_get_md5_checking(decoder)) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_process_metadata()... ");
+       if(!FLAC__seekable_stream_decoder_process_metadata(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_process_one_frame()... ");
+       if(!FLAC__seekable_stream_decoder_process_one_frame(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_flush()... ");
+       if(!FLAC__seekable_stream_decoder_flush(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       decoder_client_data.ignore_errors = true;
+       printf("testing FLAC__seekable_stream_decoder_process_one_frame()... ");
+       if(!FLAC__seekable_stream_decoder_process_one_frame(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+       decoder_client_data.ignore_errors = false;
+
+       printf("testing FLAC__seekable_stream_decoder_seek_absolute()... ");
+       if(!FLAC__seekable_stream_decoder_seek_absolute(decoder, 0)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_process_remaining_frames()... ");
+       if(!FLAC__seekable_stream_decoder_process_remaining_frames(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_get_channels()... ");
+       {
+               unsigned channels = FLAC__seekable_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__seekable_stream_decoder_get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = FLAC__seekable_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__seekable_stream_decoder_get_sample_rate()... ");
+       {
+               unsigned sample_rate = FLAC__seekable_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__seekable_stream_decoder_get_blocksize()... ");
+       {
+               unsigned blocksize = FLAC__seekable_stream_decoder_get_blocksize(decoder);
+               /* value could be anything since we're at the last block, so accept any answer */
+               printf("returned %u... OK\n", blocksize);
+       }
+
+       printf("testing FLAC__seekable_stream_decoder_get_channel_assignment()... ");
+       {
+               FLAC__ChannelAssignment ca = FLAC__seekable_stream_decoder_get_channel_assignment(decoder);
+               printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+       }
+
+       printf("testing FLAC__seekable_stream_decoder_reset()... ");
+       if(!FLAC__seekable_stream_decoder_reset(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       decoder_client_data.current_metadata_number = 0;
+
+       if(fseek(decoder_client_data.file, 0, SEEK_SET) < 0) {
+               printf("FAILED rewinding input, errno = %d\n", errno);
+               return false;
+       }
+
+       printf("testing FLAC__seekable_stream_decoder_process_whole_stream()... ");
+       if(!FLAC__seekable_stream_decoder_process_whole_stream(decoder)) {
+               state = FLAC__seekable_stream_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__SeekableStreamDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_finish()... ");
+       (void) FLAC__seekable_stream_decoder_finish(decoder);
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #2)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #2)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /* done, now leave the sequence the way we found it... */
+       num_expected_ = 0;
+       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_;
+
+       printf("testing FLAC__seekable_stream_decoder_delete()... ");
+       FLAC__seekable_stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       fclose(decoder_client_data.file);
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+static FLAC__StreamDecoderWriteStatus file_decoder_write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+{
+       (void)decoder;
+       return stream_decoder_write_callback_(0, frame, buffer, client_data);
+}
+
+static void file_decoder_metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+       (void)decoder;
+       stream_decoder_metadata_callback_(0, metadata, client_data);
+}
+
+static void file_decoder_error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       (void)decoder;
+       stream_decoder_error_callback_(0, status, client_data);
+}
+
+static FLAC__bool file_decoder_test_respond_(FLAC__FileDecoder *decoder, file_decoder_client_data_struct *dcd)
+{
+       FLAC__FileDecoderState state;
+
+       if(!FLAC__file_decoder_set_write_callback(decoder, file_decoder_write_callback_)) {
+               printf("FAILED at FLAC__file_decoder_set_write_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__file_decoder_set_metadata_callback(decoder, file_decoder_metadata_callback_)) {
+               printf("FAILED at FLAC__file_decoder_set_metadata_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__file_decoder_set_error_callback(decoder, file_decoder_error_callback_)) {
+               printf("FAILED at FLAC__file_decoder_set_error_callback(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__file_decoder_set_client_data(decoder, dcd)) {
+               printf("FAILED at FLAC__file_decoder_set_client_data(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__file_decoder_set_filename(decoder, flacfilename_)) {
+               printf("FAILED at FLAC__file_decoder_set_filename(), returned false\n");
+               return false;
+       }
+
+       if(!FLAC__file_decoder_set_md5_checking(decoder, true)) {
+               printf("FAILED at FLAC__file_decoder_set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       printf("testing FLAC__file_decoder_init()... ");
+       if((state = FLAC__file_decoder_init(decoder)) != FLAC__FILE_DECODER_OK) {
+               printf("FAILED, returned state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       dcd->current_metadata_number = 0;
+
+       printf("testing FLAC__file_decoder_process_whole_file()... ");
+       if(!FLAC__file_decoder_process_whole_file(decoder)) {
+               state = FLAC__file_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_finish()... ");
+       (void) FLAC__file_decoder_finish(decoder);
+       printf("OK\n");
+
+       return true;;
+}
+
+FLAC__bool test_file_decoder()
+{
+       FLAC__FileDecoder *decoder;
+       FLAC__FileDecoderState state;
+       seekable_stream_decoder_client_data_struct decoder_client_data;
+
+       printf("\n+++ unit test: FLAC__FileDecoder\n\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("testing FLAC__file_decoder_new()... ");
+       decoder = FLAC__file_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_write_callback()... ");
+       if(!FLAC__file_decoder_set_write_callback(decoder, file_decoder_write_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_callback()... ");
+       if(!FLAC__file_decoder_set_metadata_callback(decoder, file_decoder_metadata_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_error_callback()... ");
+       if(!FLAC__file_decoder_set_error_callback(decoder, file_decoder_error_callback_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_client_data()... ");
+       if(!FLAC__file_decoder_set_client_data(decoder, &decoder_client_data)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_filename()... ");
+       if(!FLAC__file_decoder_set_filename(decoder, flacfilename_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_md5_checking()... ");
+       if(!FLAC__file_decoder_set_md5_checking(decoder, true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_init()... ");
+       if((state = FLAC__file_decoder_init(decoder)) != FLAC__FILE_DECODER_OK) {
+               printf("FAILED, returned state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_get_state()... ");
+       state = FLAC__file_decoder_get_state(decoder);
+       printf("returned state = %u (%s)... OK\n", state, FLAC__FileDecoderStateString[state]);
+
+       decoder_client_data.current_metadata_number = 0;
+       decoder_client_data.ignore_errors = false;
+       decoder_client_data.error_occurred = false;
+
+       printf("testing FLAC__file_decoder_get_md5_checking()... ");
+       if(!FLAC__file_decoder_get_md5_checking(decoder)) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_process_metadata()... ");
+       if(!FLAC__file_decoder_process_metadata(decoder)) {
+               state = FLAC__file_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_process_one_frame()... ");
+       if(!FLAC__file_decoder_process_one_frame(decoder)) {
+               state = FLAC__file_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_seek_absolute()... ");
+       if(!FLAC__file_decoder_seek_absolute(decoder, 0)) {
+               state = FLAC__file_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_process_remaining_frames()... ");
+       if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
+               state = FLAC__file_decoder_get_state(decoder);
+               printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__FileDecoderStateString[state]);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_get_channels()... ");
+       {
+               unsigned channels = FLAC__file_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__file_decoder_get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = FLAC__file_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__file_decoder_get_sample_rate()... ");
+       {
+               unsigned sample_rate = FLAC__file_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__file_decoder_get_blocksize()... ");
+       {
+               unsigned blocksize = FLAC__file_decoder_get_blocksize(decoder);
+               /* value could be anything since we're at the last block, so accept any answer */
+               printf("returned %u... OK\n", blocksize);
+       }
+
+       printf("testing FLAC__file_decoder_get_channel_assignment()... ");
+       {
+               FLAC__ChannelAssignment ca = FLAC__file_decoder_get_channel_assignment(decoder);
+               printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+       }
+
+       printf("testing FLAC__file_decoder_finish()... ");
+       (void) FLAC__file_decoder_finish(decoder);
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__file_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__file_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__file_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__file_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__file_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_application(of app block #2)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__file_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__file_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_application(of app block #2)... ");
+       if(!FLAC__file_decoder_set_metadata_respond_application(decoder, application2_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__file_decoder_set_metadata_respond_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__file_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       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_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_all(decoder)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__file_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__file_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return 1;
+
+       /* done, now leave the sequence the way we found it... */
+       num_expected_ = 0;
+       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_;
+
+       printf("testing FLAC__file_decoder_delete()... ");
+       FLAC__file_decoder_delete(decoder);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+int test_decoders()
+{
+       init_metadata_blocks_();
+       if(!generate_file_())
+               return 1;
+
+       if(!test_stream_decoder())
+               return 1;
+
+       if(!test_seekable_stream_decoder())
+               return 1;
+
+       if(!test_file_decoder())
+               return 1;
+
+       (void) file_utils__remove_file(flacfilename_);
+       free_metadata_blocks_();
+
+       return 0;
+}
+#if 0
+typedef enum {
+    FLAC__FILE_DECODER_OK = 0,
+       FLAC__FILE_DECODER_END_OF_FILE,
+    FLAC__FILE_DECODER_ERROR_OPENING_FILE,
+    FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR,
+       FLAC__FILE_DECODER_SEEK_ERROR,
+       FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR,
+    FLAC__FILE_DECODER_ALREADY_INITIALIZED,
+    FLAC__FILE_DECODER_INVALID_CALLBACK,
+    FLAC__FILE_DECODER_UNINITIALIZED
+} FLAC__FileDecoderState;
+extern const char *FLAC__FileDecoderStateString[];
 
 /*
  * Methods for decoding the data
  */
-FLAC__bool FLAC__stream_decoder_process_whole_stream(FLAC__StreamDecoder *decoder);
-FLAC__bool FLAC__stream_decoder_process_metadata(FLAC__StreamDecoder *decoder);
-FLAC__bool FLAC__stream_decoder_process_one_frame(FLAC__StreamDecoder *decoder);
-FLAC__bool FLAC__stream_decoder_process_remaining_frames(FLAC__StreamDecoder *decoder);
+FLAC__bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder);
+FLAC__bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder);
+FLAC__bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder);
+FLAC__bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder);
 
+FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample);
 #endif