add ogg seekable stream and file encoder and decoder interfaces
authorJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 26 Sep 2003 01:56:01 +0000 (01:56 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 26 Sep 2003 01:56:01 +0000 (01:56 +0000)
28 files changed:
include/OggFLAC++/decoder.h
include/OggFLAC++/encoder.h
include/OggFLAC/Makefile.am
include/OggFLAC/all.h
include/OggFLAC/file_encoder.h [new file with mode: 0644]
include/OggFLAC/seekable_stream_encoder.h [new file with mode: 0644]
src/libOggFLAC++/Makefile.am
src/libOggFLAC++/Makefile.lite
src/libOggFLAC++/file_decoder.cpp [new file with mode: 0644]
src/libOggFLAC++/file_encoder.cpp [new file with mode: 0644]
src/libOggFLAC++/libOggFLAC++_dynamic.dsp
src/libOggFLAC++/libOggFLAC++_static.dsp
src/libOggFLAC++/seekable_stream_decoder.cpp [new file with mode: 0644]
src/libOggFLAC++/seekable_stream_encoder.cpp [new file with mode: 0644]
src/libOggFLAC/Makefile.am
src/libOggFLAC/Makefile.lite
src/libOggFLAC/file_encoder.c [new file with mode: 0644]
src/libOggFLAC/include/protected/Makefile.am
src/libOggFLAC/include/protected/all.h
src/libOggFLAC/include/protected/file_encoder.h [new file with mode: 0644]
src/libOggFLAC/include/protected/seekable_stream_encoder.h [new file with mode: 0644]
src/libOggFLAC/libOggFLAC_dynamic.dsp
src/libOggFLAC/libOggFLAC_static.dsp
src/libOggFLAC/seekable_stream_encoder.c [new file with mode: 0644]
src/test_libOggFLAC++/decoders.cpp
src/test_libOggFLAC++/encoders.cpp
src/test_libOggFLAC/decoders.c
src/test_libOggFLAC/encoders.c

index f463fa6..31510ad 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "export.h"
 
+#include "OggFLAC/file_decoder.h"
+#include "OggFLAC/seekable_stream_decoder.h"
 #include "OggFLAC/stream_decoder.h"
 // we only need this for the state abstraction really...
 #include "FLAC++/decoder.h"
  *  \ingroup oggflacpp
  *
  *  \brief
- *  This module describes the decoder layers provided by libOggFLAC++.
+ *  This module describes the three decoder layers provided by libOggFLAC++.
  *
  * The libOggFLAC++ decoder classes are object wrappers around their
- * counterparts in libOggFLAC.  Only the stream decoding layer in
- * libOggFLAC provided here.  The interface is very similar;
+ * counterparts in libOggFLAC.  All three decoding layers available in
+ * libOggFLAC are also provided here.  The interface is very similar;
  * make sure to read the \link oggflac_decoder libOggFLAC decoder module \endlink.
  *
  * The only real difference here is that instead of passing in C function
@@ -122,6 +124,10 @@ namespace OggFLAC {
                        unsigned get_sample_rate() const;
                        unsigned get_blocksize() const;
 
+                       /** Initialize the instance; as with the C interface,
+                        *  init() should be called after construction and 'set'
+                        *  calls but before any of the 'process' calls.
+                        */
                        State init();
 
                        void finish();
@@ -152,6 +158,187 @@ namespace OggFLAC {
 
                /* \} */
 
+               // ============================================================
+               //
+               //  Equivalent: OggFLAC__SeekableStreamDecoder
+               //
+               // ============================================================
+
+               /** \defgroup oggflacpp_seekable_stream_decoder OggFLAC++/decoder.h: seekable stream decoder class
+                *  \ingroup oggflacpp_decoder
+                *
+                *  \brief
+                *  This class wraps the ::OggFLAC__SeekableStreamDecoder.
+                *
+                * See the \link oggflac_seekable_stream_decoder libOggFLAC seekable stream decoder module \endlink.
+                *
+                * \{
+                */
+
+               /** This class wraps the ::OggFLAC__SeekableStreamDecoder.
+                */
+               class OggFLACPP_API SeekableStream {
+               public:
+                       class OggFLACPP_API State {
+                       public:
+                               inline State(::OggFLAC__SeekableStreamDecoderState state): state_(state) { }
+                               inline operator ::OggFLAC__SeekableStreamDecoderState() const { return state_; }
+                               inline const char *as_cstring() const { return ::OggFLAC__SeekableStreamDecoderStateString[state_]; }
+                               inline const char *resolved_as_cstring(const SeekableStream &decoder) const { return ::OggFLAC__seekable_stream_decoder_get_resolved_state_string(decoder.decoder_); }
+                       protected:
+                               ::OggFLAC__SeekableStreamDecoderState state_;
+                       };
+
+                       SeekableStream();
+                       virtual ~SeekableStream();
+
+                       bool is_valid() const;
+                       inline operator bool() const { return is_valid(); }
+
+                       bool set_serial_number(long value);
+                       bool set_md5_checking(bool value);
+                       bool set_metadata_respond(::FLAC__MetadataType type);
+                       bool set_metadata_respond_application(const FLAC__byte id[4]);
+                       bool set_metadata_respond_all();
+                       bool set_metadata_ignore(::FLAC__MetadataType type);
+                       bool set_metadata_ignore_application(const FLAC__byte id[4]);
+                       bool set_metadata_ignore_all();
+
+                       State get_state() const;
+                       FLAC::Decoder::SeekableStream::State get_FLAC_seekable_stream_decoder_state() const;
+                       FLAC::Decoder::Stream::State get_FLAC_stream_decoder_state() const;
+                       bool get_md5_checking() const;
+                       unsigned get_channels() const;
+                       ::FLAC__ChannelAssignment get_channel_assignment() const;
+                       unsigned get_bits_per_sample() const;
+                       unsigned get_sample_rate() const;
+                       unsigned get_blocksize() const;
+
+                       State init();
+
+                       bool finish();
+
+                       bool flush();
+                       bool reset();
+
+                       bool process_single();
+                       bool process_until_end_of_metadata();
+                       bool process_until_end_of_stream();
+
+                       bool seek_absolute(FLAC__uint64 sample);
+               protected:
+                       virtual ::FLAC__SeekableStreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes) = 0;
+                       virtual ::FLAC__SeekableStreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) = 0;
+                       virtual ::FLAC__SeekableStreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) = 0;
+                       virtual ::FLAC__SeekableStreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) = 0;
+                       virtual bool eof_callback() = 0;
+                       virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0;
+                       virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata) = 0;
+                       virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) = 0;
+
+                       ::OggFLAC__SeekableStreamDecoder *decoder_;
+               private:
+                       static ::FLAC__SeekableStreamDecoderReadStatus read_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+                       static ::FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+                       static ::FLAC__SeekableStreamDecoderTellStatus tell_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+                       static ::FLAC__SeekableStreamDecoderLengthStatus length_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+                       static FLAC__bool eof_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, void *client_data);
+                       static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+                       static void metadata_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
+                       static void error_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+                       // Private and undefined so you can't use them:
+                       SeekableStream(const SeekableStream &);
+                       void operator=(const SeekableStream &);
+               };
+
+               /* \} */
+
+               // ============================================================
+               //
+               //  Equivalent: OggFLAC__FileDecoder
+               //
+               // ============================================================
+
+               /** \defgroup oggflacpp_file_decoder OggFLAC++/decoder.h: file decoder class
+                *  \ingroup oggflacpp_decoder
+                *
+                *  \brief
+                *  This class wraps the ::OggFLAC__FileDecoder.
+                *
+                * See the \link oggflac_file_decoder libOggFLAC file decoder module \endlink.
+                *
+                * \{
+                */
+
+               /** This class wraps the ::OggFLAC__FileDecoder.
+                */
+               class OggFLACPP_API File {
+               public:
+                       class OggFLACPP_API State {
+                       public:
+                               inline State(::OggFLAC__FileDecoderState state): state_(state) { }
+                               inline operator ::OggFLAC__FileDecoderState() const { return state_; }
+                               inline const char *as_cstring() const { return ::OggFLAC__FileDecoderStateString[state_]; }
+                               inline const char *resolved_as_cstring(const File &decoder) const { return ::OggFLAC__file_decoder_get_resolved_state_string(decoder.decoder_); }
+                       protected:
+                               ::OggFLAC__FileDecoderState state_;
+                       };
+
+                       File();
+                       virtual ~File();
+
+                       bool is_valid() const;
+                       inline operator bool() const { return is_valid(); }
+
+                       bool set_serial_number(long value);
+                       bool set_md5_checking(bool value);
+                       bool set_filename(const char *value); //!< 'value' may not be \c NULL; use "-" for stdin
+                       bool set_metadata_respond(::FLAC__MetadataType type);
+                       bool set_metadata_respond_application(const FLAC__byte id[4]);
+                       bool set_metadata_respond_all();
+                       bool set_metadata_ignore(::FLAC__MetadataType type);
+                       bool set_metadata_ignore_application(const FLAC__byte id[4]);
+                       bool set_metadata_ignore_all();
+
+                       State get_state() const;
+                       FLAC::Decoder::File::State get_FLAC_file_decoder_state() const;
+                       FLAC::Decoder::SeekableStream::State get_FLAC_seekable_stream_decoder_state() const;
+                       FLAC::Decoder::Stream::State get_FLAC_stream_decoder_state() const;
+                       bool get_md5_checking() const;
+                       unsigned get_channels() const;
+                       ::FLAC__ChannelAssignment get_channel_assignment() const;
+                       unsigned get_bits_per_sample() const;
+                       unsigned get_sample_rate() const;
+                       unsigned get_blocksize() const;
+
+                       State init();
+
+                       bool finish();
+
+                       bool process_single();
+                       bool process_until_end_of_metadata();
+                       bool process_until_end_of_file();
+
+                       bool seek_absolute(FLAC__uint64 sample);
+               protected:
+                       virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0;
+                       virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata) = 0;
+                       virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) = 0;
+
+                       ::OggFLAC__FileDecoder *decoder_;
+               private:
+                       static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::OggFLAC__FileDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+                       static void metadata_callback_(const ::OggFLAC__FileDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
+                       static void error_callback_(const ::OggFLAC__FileDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+                       // Private and undefined so you can't use them:
+                       File(const File &);
+                       void operator=(const File &);
+               };
+
+               /* \} */
+
        };
 };
 
index b92145f..f2917c7 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "export.h"
 
+#include "OggFLAC/file_encoder.h"
+#include "OggFLAC/seekable_stream_encoder.h"
 #include "OggFLAC/stream_encoder.h"
 #include "decoder.h"
 // we only need these for the state abstractions really...
  *  \ingroup oggflacpp
  *
  *  \brief
- *  This module describes the encoder layers provided by libOggFLAC++.
+ *  This module describes the three encoder layers provided by libOggFLAC++.
  *
  * The libOggFLAC++ encoder classes are object wrappers around their
- * counterparts in libOggFLAC.  Only the stream encoding layer in
- * libOggFLAC is provided here.  The interface is very similar;
+ * counterparts in libOggFLAC.  All three encoding layers available in
+ * libOggFLAC are also provided here.  The interface is very similar;
  * make sure to read the \link oggflac_encoder libOggFLAC encoder module \endlink.
  *
  * The only real difference here is that instead of passing in C function
@@ -158,12 +160,12 @@ namespace OggFLAC {
                        bool process_interleaved(const FLAC__int32 buffer[], unsigned samples);
                protected:
                        virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame) = 0;
-                       virtual void metadata_callback(const FLAC__StreamMetadata *metadata) = 0;
+                       virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata) = 0;
 
                        ::OggFLAC__StreamEncoder *encoder_;
                private:
                        static ::FLAC__StreamEncoderWriteStatus write_callback_(const ::OggFLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
-                       static void metadata_callback_(const ::OggFLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
+                       static void metadata_callback_(const ::OggFLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
 
                        // Private and undefined so you can't use them:
                        Stream(const Stream &);
@@ -172,6 +174,200 @@ namespace OggFLAC {
 
                /* \} */
 
+               /** \defgroup oggflacpp_seekable_stream_encoder OggFLAC++/encoder.h: seekable stream encoder class
+                *  \ingroup oggflacpp_encoder
+                *
+                *  \brief
+                *  This class wraps the ::OggFLAC__SeekableStreamEncoder.
+                *
+                * See the \link oggflac_seekable_stream_encoder libOggFLAC seekable stream encoder module \endlink.
+                *
+                * \{
+                */
+
+               /** This class wraps the ::OggFLAC__SeekableStreamEncoder.
+                */
+               class OggFLACPP_API SeekableStream {
+               public:
+                       class OggFLACPP_API State {
+                       public:
+                               inline State(::OggFLAC__SeekableStreamEncoderState state): state_(state) { }
+                               inline operator ::OggFLAC__SeekableStreamEncoderState() const { return state_; }
+                               inline const char *as_cstring() const { return ::OggFLAC__SeekableStreamEncoderStateString[state_]; }
+                               inline const char *resolved_as_cstring(const SeekableStream &encoder) const { return ::OggFLAC__seekable_stream_encoder_get_resolved_state_string(encoder.encoder_); }
+                       protected:
+                               ::OggFLAC__SeekableStreamEncoderState state_;
+                       };
+
+                       SeekableStream();
+                       virtual ~SeekableStream();
+
+                       bool is_valid() const;
+                       inline operator bool() const { return is_valid(); }
+
+                       bool set_serial_number(long value);
+                       bool set_verify(bool value);
+                       bool set_streamable_subset(bool value);
+                       bool set_do_mid_side_stereo(bool value);
+                       bool set_loose_mid_side_stereo(bool value);
+                       bool set_channels(unsigned value);
+                       bool set_bits_per_sample(unsigned value);
+                       bool set_sample_rate(unsigned value);
+                       bool set_blocksize(unsigned value);
+                       bool set_max_lpc_order(unsigned value);
+                       bool set_qlp_coeff_precision(unsigned value);
+                       bool set_do_qlp_coeff_prec_search(bool value);
+                       bool set_do_escape_coding(bool value);
+                       bool set_do_exhaustive_model_search(bool value);
+                       bool set_min_residual_partition_order(unsigned value);
+                       bool set_max_residual_partition_order(unsigned value);
+                       bool set_rice_parameter_search_dist(unsigned value);
+                       bool set_total_samples_estimate(FLAC__uint64 value);
+                       bool set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+                       State    get_state() const;
+                       FLAC::Encoder::SeekableStream::State get_FLAC_seekable_stream_encoder_state() const;
+                       FLAC::Encoder::Stream::State get_FLAC_stream_encoder_state() const;
+                       FLAC::Decoder::Stream::State get_verify_decoder_state() const;
+                       void get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+                       bool     get_verify() const;
+                       bool     get_streamable_subset() const;
+                       bool     get_do_mid_side_stereo() const;
+                       bool     get_loose_mid_side_stereo() const;
+                       unsigned get_channels() const;
+                       unsigned get_bits_per_sample() const;
+                       unsigned get_sample_rate() const;
+                       unsigned get_blocksize() const;
+                       unsigned get_max_lpc_order() const;
+                       unsigned get_qlp_coeff_precision() const;
+                       bool     get_do_qlp_coeff_prec_search() const;
+                       bool     get_do_escape_coding() const;
+                       bool     get_do_exhaustive_model_search() const;
+                       unsigned get_min_residual_partition_order() const;
+                       unsigned get_max_residual_partition_order() const;
+                       unsigned get_rice_parameter_search_dist() const;
+                       FLAC__uint64 get_total_samples_estimate() const;
+
+                       State init();
+
+                       void finish();
+
+                       bool process(const FLAC__int32 * const buffer[], unsigned samples);
+                       bool process_interleaved(const FLAC__int32 buffer[], unsigned samples);
+               protected:
+                       virtual ::FLAC__SeekableStreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) = 0;
+                       virtual ::FLAC__SeekableStreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) = 0;
+                       virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame) = 0;
+
+                       ::OggFLAC__SeekableStreamEncoder *encoder_;
+               private:
+                       static ::FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+                       static ::FLAC__SeekableStreamEncoderTellStatus tell_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+                       static ::FLAC__StreamEncoderWriteStatus write_callback_(const OggFLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+                       // Private and undefined so you can't use them:
+                       SeekableStream(const SeekableStream &);
+                       void operator=(const SeekableStream &);
+               };
+
+               /* \} */
+
+               /** \defgroup oggflacpp_file_encoder OggFLAC++/encoder.h: file encoder class
+                *  \ingroup oggflacpp_encoder
+                *
+                *  \brief
+                *  This class wraps the ::OggFLAC__FileEncoder.
+                *
+                * See the \link oggflac_file_encoder libOggFLAC file encoder module \endlink.
+                *
+                * \{
+                */
+
+               /** This class wraps the ::OggFLAC__FileEncoder.
+                */
+               class OggFLACPP_API File {
+               public:
+                       class OggFLACPP_API State {
+                       public:
+                               inline State(::OggFLAC__FileEncoderState state): state_(state) { }
+                               inline operator ::OggFLAC__FileEncoderState() const { return state_; }
+                               inline const char *as_cstring() const { return ::OggFLAC__FileEncoderStateString[state_]; }
+                               inline const char *resolved_as_cstring(const File &encoder) const { return ::OggFLAC__file_encoder_get_resolved_state_string(encoder.encoder_); }
+                       protected:
+                               ::OggFLAC__FileEncoderState state_;
+                       };
+
+                       File();
+                       virtual ~File();
+
+                       bool is_valid() const;
+                       inline operator bool() const { return is_valid(); }
+
+                       bool set_serial_number(long value);
+                       bool set_verify(bool value);
+                       bool set_streamable_subset(bool value);
+                       bool set_do_mid_side_stereo(bool value);
+                       bool set_loose_mid_side_stereo(bool value);
+                       bool set_channels(unsigned value);
+                       bool set_bits_per_sample(unsigned value);
+                       bool set_sample_rate(unsigned value);
+                       bool set_blocksize(unsigned value);
+                       bool set_max_lpc_order(unsigned value);
+                       bool set_qlp_coeff_precision(unsigned value);
+                       bool set_do_qlp_coeff_prec_search(bool value);
+                       bool set_do_escape_coding(bool value);
+                       bool set_do_exhaustive_model_search(bool value);
+                       bool set_min_residual_partition_order(unsigned value);
+                       bool set_max_residual_partition_order(unsigned value);
+                       bool set_rice_parameter_search_dist(unsigned value);
+                       bool set_total_samples_estimate(FLAC__uint64 value);
+                       bool set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks);
+                       bool set_filename(const char *value);
+
+                       State    get_state() const;
+                       SeekableStream::State get_seekable_stream_encoder_state() const;
+                       FLAC::Encoder::SeekableStream::State get_FLAC_seekable_stream_encoder_state() const;
+                       FLAC::Encoder::Stream::State get_FLAC_stream_encoder_state() const;
+                       FLAC::Decoder::Stream::State get_verify_decoder_state() const;
+                       void get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+                       bool     get_verify() const;
+                       bool     get_streamable_subset() const;
+                       bool     get_do_mid_side_stereo() const;
+                       bool     get_loose_mid_side_stereo() const;
+                       unsigned get_channels() const;
+                       unsigned get_bits_per_sample() const;
+                       unsigned get_sample_rate() const;
+                       unsigned get_blocksize() const;
+                       unsigned get_max_lpc_order() const;
+                       unsigned get_qlp_coeff_precision() const;
+                       bool     get_do_qlp_coeff_prec_search() const;
+                       bool     get_do_escape_coding() const;
+                       bool     get_do_exhaustive_model_search() const;
+                       unsigned get_min_residual_partition_order() const;
+                       unsigned get_max_residual_partition_order() const;
+                       unsigned get_rice_parameter_search_dist() const;
+                       FLAC__uint64 get_total_samples_estimate() const;
+
+                       State init();
+
+                       void finish();
+
+                       bool process(const FLAC__int32 * const buffer[], unsigned samples);
+                       bool process_interleaved(const FLAC__int32 buffer[], unsigned samples);
+               protected:
+                       virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
+
+                       ::OggFLAC__FileEncoder *encoder_;
+               private:
+                       static void progress_callback_(const ::OggFLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+                       // Private and undefined so you can't use them:
+                       File(const Stream &);
+                       void operator=(const Stream &);
+               };
+
+               /* \} */
+
        };
 };
 
index ce88f73..8d710de 100644 (file)
@@ -36,5 +36,9 @@ oggflaccincludedir = $(includedir)/OggFLAC
 oggflaccinclude_HEADERS = \
        all.h \
        export.h \
+       file_decoder.h \
+       file_encoder.h \
+       seekable_stream_decoder.h \
+       seekable_stream_encoder.h \
        stream_decoder.h \
        stream_encoder.h
index d690700..2f2730b 100644 (file)
 
 #include "export.h"
 
+#include "file_decoder.h"
+#include "file_encoder.h"
+#include "seekable_stream_decoder.h"
+#include "seekable_stream_encoder.h"
 #include "stream_decoder.h"
 #include "stream_encoder.h"
 
diff --git a/include/OggFLAC/file_encoder.h b/include/OggFLAC/file_encoder.h
new file mode 100644 (file)
index 0000000..015a7d4
--- /dev/null
@@ -0,0 +1,878 @@
+/* libOggFLAC - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OggFLAC__FILE_ENCODER_H
+#define OggFLAC__FILE_ENCODER_H
+
+#include "export.h"
+#include "seekable_stream_encoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/OggFLAC/file_encoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the file
+ *  encoder.
+ *
+ *  See the detailed documentation in the
+ *  \link oggflac_file_encoder file encoder \endlink module.
+ */
+
+/** \defgroup oggflac_file_encoder OggFLAC/file_encoder.h: file encoder interface
+ *  \ingroup oggflac_encoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the file
+ *  encoder.  Unlink the Ogg stream and seekable stream encoders, which
+ *  derive from their FLAC counterparts, the Ogg file encoder is derived
+ *  from the Ogg seekable stream encoder.
+ *
+ * The interface here is nearly identical to FLAC's file
+ * encoder, including the callbacks, with the addition of
+ * OggFLAC__file_encoder_set_serial_number().  See the
+ * \link flac_file_encoder FLAC file encoder module \endlink
+ * for full documentation.
+ *
+ * \{
+ */
+
+
+/** State values for a OggFLAC__FileEncoder
+ *
+ *  The encoder's state can be obtained by calling OggFLAC__file_encoder_get_state().
+ */
+typedef enum {
+
+       OggFLAC__FILE_ENCODER_OK = 0,
+       /**< The encoder is in the normal OK state. */
+
+       OggFLAC__FILE_ENCODER_NO_FILENAME,
+       /**< OggFLAC__file_encoder_init() was called without first calling
+        * OggFLAC__file_encoder_set_filename().
+        */
+
+       OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR,
+       /**< An error occurred in the underlying seekable stream encoder;
+        * check OggFLAC__file_encoder_get_seekable_stream_encoder_state().
+        */
+
+       OggFLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING,
+       /**< A fatal error occurred while writing to the encoded file. */
+
+       OggFLAC__FILE_ENCODER_ERROR_OPENING_FILE,
+       /**< An error occurred opening the output file for writing. */
+
+       OggFLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR,
+       /**< Memory allocation failed. */
+
+       OggFLAC__FILE_ENCODER_ALREADY_INITIALIZED,
+       /**< OggFLAC__file_encoder_init() was called when the encoder was
+        * already initialized, usually because
+        * OggFLAC__file_encoder_finish() was not called.
+        */
+
+       OggFLAC__FILE_ENCODER_UNINITIALIZED
+       /**< The encoder is in the uninitialized state. */
+
+} OggFLAC__FileEncoderState;
+
+/** Maps a FLAC__FileEncoderState to a C string.
+ *
+ *  Using a FLAC__FileEncoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern OggFLAC_API const char * const OggFLAC__FileEncoderStateString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__FileEncoder
+ *
+ ***********************************************************************/
+
+struct OggFLAC__FileEncoderProtected;
+struct OggFLAC__FileEncoderPrivate;
+/** The opaque structure definition for the file encoder type.
+ *  See the \link oggflac_file_encoder file encoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+       struct OggFLAC__FileEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+       struct OggFLAC__FileEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} OggFLAC__FileEncoder;
+
+/** Signature for the progress callback.
+ *  See OggFLAC__file_encoder_set_progress_callback()
+ *  and FLAC__FileEncoderProgressCallback for more info.
+ *
+ * \param  encoder          The encoder instance calling the callback.
+ * \param  bytes_written    Bytes written so far.
+ * \param  samples_written  Samples written so far.
+ * \param  frames_written   Frames written so far.
+ * \param  total_frames_estimate  The estimate of the total number of
+ *                                frames to be written.
+ * \param  client_data      The callee's client data set through
+ *                          OggFLAC__file_encoder_set_client_data().
+ */
+typedef void (*OggFLAC__FileEncoderProgressCallback)(const OggFLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new file encoder instance.  The instance is created with
+ *  default settings; see the individual OggFLAC__file_encoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval OggFLAC__FileEncoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+OggFLAC_API OggFLAC__FileEncoder *OggFLAC__file_encoder_new();
+
+/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder  A pointer to an existing encoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+OggFLAC_API void OggFLAC__file_encoder_delete(OggFLAC__FileEncoder *encoder);
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream.
+ *
+ * \default \c NULL, 0
+ * \param  encoder        An encoder instance to set.
+ * \param  serial_number  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_serial_number(OggFLAC__FileEncoder *encoder, long serial_number);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_verify().
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_verify(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_streamable_subset().
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_streamable_subset(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_mid_side_stereo(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_loose_mid_side_stereo(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_channels().
+ *
+ * \default \c 2
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_channels(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_bits_per_sample().
+ *
+ * \warning
+ * Do not feed the encoder data that is wider than the value you
+ * set here or you will generate an invalid stream.
+ *
+ * \default \c 16
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_bits_per_sample(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_sample_rate().
+ *
+ * \default \c 44100
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_sample_rate(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_blocksize().
+ *
+ * \default \c 1152
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_blocksize(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_max_lpc_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_max_lpc_order(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision().
+ *
+ * \note
+ * In the current implementation, qlp_coeff_precision + bits_per_sample must
+ * be less than 32.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_qlp_coeff_precision(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_qlp_coeff_prec_search(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_do_escape_coding().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_escape_coding(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_exhaustive_model_search(OggFLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_min_residual_partition_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_min_residual_partition_order(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_max_residual_partition_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_max_residual_partition_order(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_rice_parameter_search_dist(OggFLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_total_samples_estimate().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_total_samples_estimate(OggFLAC__FileEncoder *encoder, FLAC__uint64 value);
+
+/** This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_set_metadata().
+ *
+ * \default \c NULL, 0
+ * \param  encoder     An encoder instance to set.
+ * \param  metadata    See above.
+ * \param  num_blocks  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_metadata(OggFLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Set the output file name encode to.
+ *
+ * \note
+ * The filename is mandatory and must be set before initialization.
+ *
+ * \note
+ * Unlike the OggFLAC__FileDecoder, the filename does not interpret "-" for
+ * \c stdout; writing to \c stdout is not relevant in the file encoder.
+ *
+ * \default \c NULL
+ * \param  encoder  A encoder instance to set.
+ * \param  value    The output file name.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, or there was a memory
+ *    allocation error, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_filename(OggFLAC__FileEncoder *encoder, const char *value);
+
+/** Set the progress callback.
+ *  The supplied function will be called when the encoder has finished
+ *  writing a frame.  The \c total_frames_estimate argument to the callback
+ *  will be based on the value from
+ *  OggFLAC__file_encoder_set_total_samples_estimate().
+ *
+ * \note
+ * Unlike most other callbacks, the progress callback is \b not mandatory
+ * and need not be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_progress_callback(OggFLAC__FileEncoder *encoder, OggFLAC__FileEncoderProgressCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_client_data(OggFLAC__FileEncoder *encoder, void *value);
+
+/** Get the current encoder state.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__FileEncoderState
+ *    The current encoder state.
+ */
+OggFLAC_API OggFLAC__FileEncoderState OggFLAC__file_encoder_get_state(const OggFLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying seekable stream encoder.
+ *  Useful when the file encoder state is
+ *  \c OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval OggFLAC__SeekableStreamEncoderState
+ *    The seekable stream encoder state.
+ */
+OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__file_encoder_get_seekable_stream_encoder_state(const OggFLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying FLAC seekable stream encoder.
+ *  Useful when the file encoder state is
+ *  \c OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the seekable stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__SeekableStreamEncoderState
+ *    The seekable stream encoder state.
+ */
+OggFLAC_API FLAC__SeekableStreamEncoderState OggFLAC__file_encoder_get_FLAC_seekable_stream_encoder_state(const OggFLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying FLAC stream encoder.
+ *  Useful when the file encoder state is
+ *  \c OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the seekable stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the FLAC seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    The seekable stream encoder state.
+ */
+OggFLAC_API FLAC__StreamEncoderState OggFLAC__file_encoder_get_FLAC_stream_encoder_state(const OggFLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying stream encoder's verify decoder.
+ *  Useful when the file encoder state is
+ *  \c OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the seekable stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the FLAC seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR
+ *  and the FLAC stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The stream encoder state.
+ */
+OggFLAC_API FLAC__StreamDecoderState OggFLAC__file_encoder_get_verify_decoder_state(const OggFLAC__FileEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ *  This version automatically resolves
+ *  \c OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR by getting the
+ *  seekable stream encoder's state.
+ *
+ * \param  encoder  A encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval const char *
+ *    The encoder state as a C string.  Do not modify the contents.
+ */
+OggFLAC_API const char *OggFLAC__file_encoder_get_resolved_state_string(const OggFLAC__FileEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ *  Inherited from OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats().
+ *  Useful when the file encoder state is
+ *  \c OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the seekable stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the FLAC seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR
+ *  and the FLAC stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \param  absolute_sample  The absolute sample number of the mismatch.
+ * \param  frame_number  The number of the frame in which the mismatch occurred.
+ * \param  channel       The channel in which the mismatch occurred.
+ * \param  sample        The number of the sample (relative to the frame) in
+ *                       which the mismatch occurred.
+ * \param  expected      The expected value for the sample in question.
+ * \param  got           The actual value returned by the decoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+OggFLAC_API void OggFLAC__file_encoder_get_verify_decoder_error_stats(const OggFLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** Get the "verify" flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_verify().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_set_verify().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_verify(const OggFLAC__FileEncoder *encoder);
+
+/** Get the "streamable subset" flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_streamable_subset().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_set_streamable_subset().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_streamable_subset(const OggFLAC__FileEncoder *encoder);
+
+/** Get the "mid/side stereo coding" flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_get_do_mid_side_stereo().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_mid_side_stereo(const OggFLAC__FileEncoder *encoder);
+
+/** Get the "adaptive mid/side switching" flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_set_loose_mid_side_stereo().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_loose_mid_side_stereo(const OggFLAC__FileEncoder *encoder);
+
+/** Get the number of input channels being processed.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_channels().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_channels().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_channels(const OggFLAC__FileEncoder *encoder);
+
+/** Get the input sample resolution setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_bits_per_sample().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_bits_per_sample().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_bits_per_sample(const OggFLAC__FileEncoder *encoder);
+
+/** Get the input sample rate setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_sample_rate().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_sample_rate().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_sample_rate(const OggFLAC__FileEncoder *encoder);
+
+/** Get the blocksize setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_blocksize().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_blocksize().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_blocksize(const OggFLAC__FileEncoder *encoder);
+
+/** Get the maximum LPC order setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_max_lpc_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_max_lpc_order().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_max_lpc_order(const OggFLAC__FileEncoder *encoder);
+
+/** Get the quantized linear predictor coefficient precision setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_qlp_coeff_precision().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_qlp_coeff_precision(const OggFLAC__FileEncoder *encoder);
+
+/** Get the qlp coefficient precision search flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_set_do_qlp_coeff_prec_search().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__FileEncoder *encoder);
+
+/** Get the "escape coding" flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_do_escape_coding().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_set_do_escape_coding().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_escape_coding(const OggFLAC__FileEncoder *encoder);
+
+/** Get the exhaustive model search flag.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__file_encoder_set_do_exhaustive_model_search().
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_exhaustive_model_search(const OggFLAC__FileEncoder *encoder);
+
+/** Get the minimum residual partition order setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_min_residual_partition_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_min_residual_partition_order().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_min_residual_partition_order(const OggFLAC__FileEncoder *encoder);
+
+/** Get maximum residual partition order setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_max_residual_partition_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_max_residual_partition_order().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_max_residual_partition_order(const OggFLAC__FileEncoder *encoder);
+
+/** Get the Rice parameter search distance setting.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__file_encoder_set_rice_parameter_search_dist().
+ */
+OggFLAC_API unsigned OggFLAC__file_encoder_get_rice_parameter_search_dist(const OggFLAC__FileEncoder *encoder);
+
+/** Get the previously set estimate of the total samples to be encoded.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_get_total_samples_estimate().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ *    See OggFLAC__file_encoder_set_total_samples_estimate().
+ */
+OggFLAC_API FLAC__uint64 OggFLAC__file_encoder_get_total_samples_estimate(const OggFLAC__FileEncoder *encoder);
+
+/** Initialize the encoder instance.
+ *  Should be called after OggFLAC__file_encoder_new() and
+ *  OggFLAC__file_encoder_set_*() but before OggFLAC__file_encoder_process()
+ *  or OggFLAC__file_encoder_process_interleaved().  Will set and return
+ *  the encoder state, which will be OggFLAC__FILE_ENCODER_OK if
+ *  initialization succeeded.
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval OggFLAC__FileEncoderState
+ *    \c OggFLAC__FILE_ENCODER_OK if initialization was successful; see
+ *    OggFLAC__FileEncoderState for the meanings of other return values.
+ */
+OggFLAC_API OggFLAC__FileEncoderState OggFLAC__file_encoder_init(OggFLAC__FileEncoder *encoder);
+
+/** Finish the encoding process.
+ *  Flushes the encoding buffer, releases resources, resets the encoder
+ *  settings to their defaults, and returns the encoder state to
+ *  OggFLAC__FILE_ENCODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated encode, it is not strictly
+ *  necessary to call this immediately before OggFLAC__file_encoder_delete()
+ *  but it is good practice to match every OggFLAC__file_encoder_init()
+ *  with a OggFLAC__file_encoder_finish().
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+OggFLAC_API void OggFLAC__file_encoder_finish(OggFLAC__FileEncoder *encoder);
+
+/** Submit data for encoding.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_process().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of pointers to each channel's signal.
+ * \param  samples  The number of samples in one channel.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code OggFLAC__file_encoder_get_state(encoder) == OggFLAC__FILE_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with OggFLAC__file_encoder_get_state() to see what
+ *    went wrong.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_process(OggFLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ *  This is inherited from OggFLAC__SeekableStreamEncoder; see
+ *  OggFLAC__seekable_stream_encoder_process_interleaved().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of channel-interleaved data (see above).
+ * \param  samples  The number of samples in one channel, the same as for
+ *                  OggFLAC__file_encoder_process().  For example, if
+ *                  encoding two channels, \c 1000 \a samples corresponds
+ *                  to a \a buffer of 2000 values.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code OggFLAC__file_encoder_get_state(encoder) == OggFLAC__FILE_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with OggFLAC__file_encoder_get_state() to see what
+ *    went wrong.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_process_interleaved(OggFLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/OggFLAC/seekable_stream_encoder.h b/include/OggFLAC/seekable_stream_encoder.h
new file mode 100644 (file)
index 0000000..1a0cb85
--- /dev/null
@@ -0,0 +1,853 @@
+/* libOggFLAC - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OggFLAC__SEEKABLE_STREAM_ENCODER_H
+#define OggFLAC__SEEKABLE_STREAM_ENCODER_H
+
+#include "export.h"
+
+#include "FLAC/seekable_stream_encoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/OggFLAC/seekable_stream_encoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the seekable
+ *  stream encoder.
+ *
+ *  See the detailed documentation in the
+ *  \link oggflac_seekable_stream_encoder seekable stream encoder \endlink module.
+ */
+
+/** \defgroup oggflac_seekable_stream_encoder OggFLAC/seekable_stream_encoder.h: seekable stream encoder interface
+ *  \ingroup oggflac_encoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the seekable
+ *  stream encoder.  The Ogg seekable stream encoder is derived
+ *  from the FLAC seekable stream encoder.
+ *
+ * The interface here is nearly identical to FLAC's seekable stream
+ * encoder, including the callbacks, with the addition of
+ * OggFLAC__seekable_stream_encoder_set_serial_number().  See the
+ * \link flac_seekable_stream_encoder FLAC seekable stream encoder module \endlink
+ * for full documentation.
+ *
+ * \{
+ */
+
+
+/** State values for an OggFLAC__SeekableStreamEncoder
+ *
+ *  The encoder's state can be obtained by calling OggFLAC__stream_encoder_get_state().
+ */
+typedef enum {
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_OK = 0,
+       /**< The encoder is in the normal OK state. */
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR,
+       /**< An error occurred in the underlying Ogg layer.  */
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR,
+       /**< An error occurred in the underlying FLAC seekable stream encoder;
+        * check OggFLAC__stream_encoder_get_FLAC_seekable_stream_encoder_state().
+        */
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK,
+       /**< The encoder was initialized before setting all the required callbacks. */
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR,
+       /**< Memory allocation failed. */
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED,
+       /**< OggFLAC__seekable_stream_encoder_init() was called when the encoder was
+        * already initialized, usually because
+        * OggFLAC__seekable_stream_encoder_finish() was not called.
+        */
+
+       OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED
+       /**< The encoder is in the uninitialized state. */
+
+} OggFLAC__SeekableStreamEncoderState;
+
+/** Maps an OggFLAC__StreamEncoderState to a C string.
+ *
+ *  Using an OggFLAC__StreamEncoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern OggFLAC_API const char * const OggFLAC__SeekableStreamEncoderStateString[];
+
+
+/***********************************************************************
+ *
+ * class OggFLAC__StreamEncoder
+ *
+ ***********************************************************************/
+
+struct OggFLAC__SeekableStreamEncoderProtected;
+struct OggFLAC__SeekableStreamEncoderPrivate;
+/** The opaque structure definition for the seekable stream encoder type.
+ *  See the \link oggflac_seekable_stream_encoder seekable stream encoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+       struct OggFLAC__SeekableStreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+       struct OggFLAC__SeekableStreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} OggFLAC__SeekableStreamEncoder;
+
+/** Signature for the seek callback.
+ *  See OggFLAC__seekable_stream_encoder_set_seek_callback()
+ *  and FLAC__SeekableStreamEncoderSeekCallback for more info.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  absolute_byte_offset  The offset from the beginning of the stream
+ *                               to seek to.
+ * \param  client_data  The callee's client data set through
+ *                      OggFLAC__seekable_stream_encoder_set_client_data().
+ * \retval FLAC__SeekableStreamEncoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamEncoderSeekStatus (*OggFLAC__SeekableStreamEncoderSeekCallback)(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *  See OggFLAC__seekable_stream_encoder_set_tell_callback()
+ *  and FLAC__SeekableStreamEncoderTellCallback for more info.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  absolute_byte_offset  The address at which to store the current
+ *                               position of the output.
+ * \param  client_data  The callee's client data set through
+ *                      OggFLAC__seekable_stream_encoder_set_client_data().
+ * \retval FLAC__SeekableStreamEncoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamEncoderTellStatus (*OggFLAC__SeekableStreamEncoderTellCallback)(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the write callback.
+ *  See OggFLAC__seekable_stream_encoder_set_write_callback()
+ *  and FLAC__SeekableStreamEncoderWriteCallback for more info.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  buffer   An array of encoded data of length \a bytes.
+ * \param  bytes    The byte length of \a buffer.
+ * \param  samples  The number of samples encoded by \a buffer.
+ *                  \c 0 has a special meaning; see
+ *                  OggFLAC__seekable_stream_encoder_set_write_callback().
+ * \param  current_frame  The number of current frame being encoded.
+ * \param  client_data  The callee's client data set through
+ *                      OggFLAC__seekable_stream_encoder_set_client_data().
+ * \retval FLAC__StreamEncoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderWriteStatus (*OggFLAC__SeekableStreamEncoderWriteCallback)(const OggFLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new seekable stream encoder instance.  The instance is created with
+ *  default settings; see the individual OggFLAC__seekable_stream_encoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval OggFLAC__SeekableStreamEncoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+OggFLAC_API OggFLAC__SeekableStreamEncoder *OggFLAC__seekable_stream_encoder_new();
+
+/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder  A pointer to an existing encoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+OggFLAC_API void OggFLAC__seekable_stream_encoder_delete(OggFLAC__SeekableStreamEncoder *encoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream.
+ *
+ * \default \c NULL, 0
+ * \param  encoder        An encoder instance to set.
+ * \param  serial_number  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_serial_number(OggFLAC__SeekableStreamEncoder *encoder, long serial_number);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_verify()
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_verify(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_streamable_subset()
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_streamable_subset(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_do_mid_side_stereo()
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_loose_mid_side_stereo()
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_channels()
+ *
+ * \default \c 2
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_channels(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_bits_per_sample()
+ *
+ * \default \c 16
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_bits_per_sample(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_sample_rate()
+ *
+ * \default \c 44100
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_sample_rate(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_blocksize()
+ *
+ * \default \c 1152
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_blocksize(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_max_lpc_order()
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_lpc_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_qlp_coeff_precision()
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_qlp_coeff_prec_search()
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_do_escape_coding()
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_escape_coding(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_do_exhaustive_model_search()
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_min_residual_partition_order()
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_min_residual_partition_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_max_residual_partition_order()
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_residual_partition_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_rice_parameter_search_dist()
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist(OggFLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_total_samples_estimate()
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_total_samples_estimate(OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_set_metadata()
+ *
+ * \default \c NULL, 0
+ * \param  encoder     An encoder instance to set.
+ * \param  metadata    See above.
+ * \param  num_blocks  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_metadata(OggFLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Set the seek callback.
+ *  The supplied function will be called when the encoder needs to seek
+ *  the output stream.  The encoder will pass the absolute byte offset
+ *  to seek to, 0 meaning the beginning of the stream.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_seek_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderSeekCallback value);
+
+/** Set the tell callback.
+ *  The supplied function will be called when the encoder needs to know
+ *  the current position of the output stream.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_tell_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderTellCallback value);
+
+/** Set the write callback.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_write_callback().
+ *
+ * \note
+ * Unlike the FLAC seekable stream encoder write callback, the Ogg
+ * seekable stream encoder write callback will be called twice when
+ * writing audio frames; once for the page header, and once for the page
+ * body.  When writing the page header, the \a samples argument to the
+ * write callback will be \c 0.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_write_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderWriteCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_client_data(OggFLAC__SeekableStreamEncoder *encoder, void *value);
+
+/** Get the current encoder state.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval OggFLAC__SeekableStreamEncoderState
+ *    The current encoder state.
+ */
+OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_get_state(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Get the state of the underlying FLAC seekable stream encoder.
+ *  Useful when the seekable stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__SeekableStreamEncoderState
+ *    The FLAC seeekable stream encoder state.
+ */
+OggFLAC_API FLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Get the state of the underlying FLAC stream encoder.
+ *  Useful when the seekable stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the FLAC seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    The FLAC stream encoder state.
+ */
+OggFLAC_API FLAC__StreamEncoderState OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Get the state of the underlying FLAC encoder's verify decoder.
+ *  Useful when the stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the FLAC seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR
+ *  and the FLAC stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The FLAC verify decoder state.
+ */
+OggFLAC_API FLAC__StreamDecoderState OggFLAC__seekable_stream_encoder_get_verify_decoder_state(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ *  This version automatically resolves
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  by getting the FLAC seekable stream encoder's resolved state.
+ *
+ * \param  encoder  A encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval const char *
+ *    The encoder state as a C string.  Do not modify the contents.
+ */
+OggFLAC_API const char *OggFLAC__seekable_stream_encoder_get_resolved_state_string(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ *  Inherited from FLAC__seekable_stream_encoder_get_verify_decoder_error_stats().
+ *  Useful when the stream encoder state is
+ *  \c OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR
+ *  and the FLAC seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR
+ *  and the FLAC stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \param  absolute_sample  The absolute sample number of the mismatch.
+ * \param  frame_number  The number of the frame in which the mismatch occurred.
+ * \param  channel       The channel in which the mismatch occurred.
+ * \param  sample        The number of the sample (relative to the frame) in
+ *                       which the mismatch occurred.
+ * \param  expected      The expected value for the sample in question.
+ * \param  got           The actual value returned by the decoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code absolute_sample != NULL \endcode
+ *    \code frame_number != NULL \endcode
+ *    \code channel != NULL \endcode
+ *    \code sample != NULL \endcode
+ *    \code expected != NULL \endcode
+ */
+OggFLAC_API void OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_verify()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_set_verify().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_verify(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_streamable_subset()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_set_streamable_subset().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_streamable_subset(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_do_mid_side_stereo()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_loose_mid_side_stereo()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_channels()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_channels().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_channels(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_bits_per_sample()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_bits_per_sample().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_bits_per_sample(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_sample_rate()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_sample_rate().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_sample_rate(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_blocksize()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_blocksize().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_blocksize(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_max_lpc_order()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_max_lpc_order().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_lpc_order(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_qlp_coeff_precision()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_do_escape_coding()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_set_do_escape_coding().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_escape_coding(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_do_exhaustive_model_search()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search().
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_min_residual_partition_order()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_min_residual_partition_order().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_man_residual_partition_order()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_max_residual_partition_order().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_rice_parameter_search_dist()
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist().
+ */
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_get_total_samples_estimate()
+ *
+ * \param  encoder  An encoder instance to set.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ *    See OggFLAC__seekable_stream_encoder_get_total_samples_estimate().
+ */
+OggFLAC_API FLAC__uint64 OggFLAC__seekable_stream_encoder_get_total_samples_estimate(const OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Initialize the encoder instance.
+ *  Should be called after OggFLAC__seekable_stream_encoder_new() and
+ *  OggFLAC__seekable_stream_encoder_set_*() but before OggFLAC__seekable_stream_encoder_process()
+ *  or OggFLAC__seekable_stream_encoder_process_interleaved().  Will set and return
+ *  the encoder state, which will be OggFLAC__SEEKABLE_STREAM_ENCODER_OK if
+ *  initialization succeeded.
+ *
+ *  The call to OggFLAC__seekable_stream_encoder_init() currently will also immediately
+ *  call the write callback several times, once with the \c fLaC signature,
+ *  and once for each encoded metadata block.
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval OggFLAC__SeekableStreamEncoderState
+ *    \c OggFLAC__SEEKABLE_STREAM_ENCODER_OK if initialization was successful; see
+ *    OggFLAC__SeekableStreamEncoderState for the meanings of other return values.
+ */
+OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_init(OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Finish the encoding process.
+ *  Flushes the encoding buffer, releases resources, resets the encoder
+ *  settings to their defaults, and returns the encoder state to
+ *  OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED.  Note that this can generate
+ *  one or more write callbacks before returning.
+ *
+ *  In the event of a prematurely-terminated encode, it is not strictly
+ *  necessary to call this immediately before OggFLAC__seekable_stream_encoder_delete()
+ *  but it is good practice to match every OggFLAC__seekable_stream_encoder_init()
+ *  with an OggFLAC__seekable_stream_encoder_finish().
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+OggFLAC_API void OggFLAC__seekable_stream_encoder_finish(OggFLAC__SeekableStreamEncoder *encoder);
+
+/** Submit data for encoding.
+ * This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_process().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of pointers to each channel's signal.
+ * \param  samples  The number of samples in one channel.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code OggFLAC__seekable_stream_encoder_get_state(encoder) == OggFLAC__SEEKABLE_STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with OggFLAC__seekable_stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ * This is inherited from FLAC__SeekableStreamEncoder; see FLAC__seekable_stream_encoder_process_interleaved().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of channel-interleaved data (see above).
+ * \param  samples  The number of samples in one channel, the same as for
+ *                  OggFLAC__seekable_stream_encoder_process().  For example, if
+ *                  encoding two channels, \c 1000 \a samples corresponds
+ *                  to a \a buffer of 2000 values.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code OggFLAC__seekable_stream_encoder_get_state(encoder) == OggFLAC__SEEKABLE_STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with OggFLAC__seekable_stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process_interleaved(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 10ba4ad..3239133 100644 (file)
@@ -45,5 +45,9 @@ libOggFLAC___la_LDFLAGS = -version-info 0:4:0
 libOggFLAC___la_LIBADD = ../libOggFLAC/libOggFLAC.la
 
 libOggFLAC___la_SOURCES = \
+       file_decoder.cpp \
+       file_encoder.cpp \
+       seekable_stream_decoder.cpp \
+       seekable_stream_encoder.cpp \
        stream_decoder.cpp \
        stream_encoder.cpp
index 0edd3d9..4f3771f 100644 (file)
@@ -38,6 +38,10 @@ LIB_NAME = libOggFLAC++
 INCLUDES = -I$(topdir)/include
 
 SRCS_CPP = \
+       file_decoder.cpp \
+       file_encoder.cpp \
+       seekable_stream_decoder.cpp \
+       seekable_stream_encoder.cpp \
        stream_decoder.cpp \
        stream_encoder.cpp
 
diff --git a/src/libOggFLAC++/file_decoder.cpp b/src/libOggFLAC++/file_decoder.cpp
new file mode 100644 (file)
index 0000000..678908e
--- /dev/null
@@ -0,0 +1,237 @@
+/* libOggFLAC++ - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "OggFLAC++/decoder.h"
+#include "FLAC/assert.h"
+
+namespace OggFLAC {
+       namespace Decoder {
+
+               File::File():
+               decoder_(::OggFLAC__file_decoder_new())
+               { }
+
+               File::~File()
+               {
+                       if(0 != decoder_) {
+                               (void) ::OggFLAC__file_decoder_finish(decoder_);
+                               ::OggFLAC__file_decoder_delete(decoder_);
+                       }
+               }
+
+               bool File::is_valid() const
+               {
+                       return 0 != decoder_;
+               }
+
+               bool File::set_serial_number(long value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_decoder_set_serial_number(decoder_, value);
+               }
+
+               bool File::set_md5_checking(bool value)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_md5_checking(decoder_, value);
+               }
+
+               bool File::set_filename(const char *value)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_filename(decoder_, value);
+               }
+
+               bool File::set_metadata_respond(::FLAC__MetadataType type)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_metadata_respond(decoder_, type);
+               }
+
+               bool File::set_metadata_respond_application(const FLAC__byte id[4])
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_metadata_respond_application(decoder_, id);
+               }
+
+               bool File::set_metadata_respond_all()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_metadata_respond_all(decoder_);
+               }
+
+               bool File::set_metadata_ignore(::FLAC__MetadataType type)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_metadata_ignore(decoder_, type);
+               }
+
+               bool File::set_metadata_ignore_application(const FLAC__byte id[4])
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_metadata_ignore_application(decoder_, id);
+               }
+
+               bool File::set_metadata_ignore_all()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_set_metadata_ignore_all(decoder_);
+               }
+
+               File::State File::get_state() const
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return State(::OggFLAC__file_decoder_get_state(decoder_));
+               }
+
+               FLAC::Decoder::File::State File::get_FLAC_file_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::File::State(::OggFLAC__file_decoder_get_FLAC_file_decoder_state(decoder_));
+               }
+
+               FLAC::Decoder::SeekableStream::State File::get_FLAC_seekable_stream_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::SeekableStream::State(::OggFLAC__file_decoder_get_FLAC_seekable_stream_decoder_state(decoder_));
+               }
+
+               FLAC::Decoder::Stream::State File::get_FLAC_stream_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::Stream::State(::OggFLAC__file_decoder_get_FLAC_stream_decoder_state(decoder_));
+               }
+
+               bool File::get_md5_checking() const
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_get_md5_checking(decoder_);
+               }
+
+               unsigned File::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_decoder_get_channels(decoder_);
+               }
+
+               ::FLAC__ChannelAssignment File::get_channel_assignment() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_decoder_get_channel_assignment(decoder_);
+               }
+
+               unsigned File::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_decoder_get_bits_per_sample(decoder_);
+               }
+
+               unsigned File::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_decoder_get_sample_rate(decoder_);
+               }
+
+               unsigned File::get_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_decoder_get_blocksize(decoder_);
+               }
+
+               File::State File::init()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       ::OggFLAC__file_decoder_set_write_callback(decoder_, write_callback_);
+                       ::OggFLAC__file_decoder_set_metadata_callback(decoder_, metadata_callback_);
+                       ::OggFLAC__file_decoder_set_error_callback(decoder_, error_callback_);
+                       ::OggFLAC__file_decoder_set_client_data(decoder_, (void*)this);
+                       return State(::OggFLAC__file_decoder_init(decoder_));
+               }
+
+               bool File::finish()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_finish(decoder_);
+               }
+
+               bool File::process_single()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_process_single(decoder_);
+               }
+
+               bool File::process_until_end_of_metadata()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_process_until_end_of_metadata(decoder_);
+               }
+
+               bool File::process_until_end_of_file()
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_process_until_end_of_file(decoder_);
+               }
+
+               bool File::seek_absolute(FLAC__uint64 sample)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return (bool)::OggFLAC__file_decoder_seek_absolute(decoder_, sample);
+               }
+
+               ::FLAC__StreamDecoderWriteStatus File::write_callback_(const ::OggFLAC__FileDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       File *instance = reinterpret_cast<File *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->write_callback(frame, buffer);
+               }
+
+               void File::metadata_callback_(const ::OggFLAC__FileDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       File *instance = reinterpret_cast<File *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->metadata_callback(metadata);
+               }
+
+               void File::error_callback_(const ::OggFLAC__FileDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       File *instance = reinterpret_cast<File *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->error_callback(status);
+               }
+
+       };
+};
diff --git a/src/libOggFLAC++/file_encoder.cpp b/src/libOggFLAC++/file_encoder.cpp
new file mode 100644 (file)
index 0000000..74fe683
--- /dev/null
@@ -0,0 +1,354 @@
+/* libOggFLAC++ - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "OggFLAC++/encoder.h"
+#include "FLAC/assert.h"
+
+namespace OggFLAC {
+       namespace Encoder {
+
+               File::File():
+               encoder_(::OggFLAC__file_encoder_new())
+               { }
+
+               File::~File()
+               {
+                       if(0 != encoder_) {
+                               ::OggFLAC__file_encoder_finish(encoder_);
+                               ::OggFLAC__file_encoder_delete(encoder_);
+                       }
+               }
+
+               bool File::set_serial_number(long value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_serial_number(encoder_, value);
+               }
+
+               bool File::is_valid() const
+               {
+                       return 0 != encoder_;
+               }
+
+               bool File::set_verify(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_verify(encoder_, value);
+               }
+
+               bool File::set_streamable_subset(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_streamable_subset(encoder_, value);
+               }
+
+               bool File::set_do_mid_side_stereo(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_do_mid_side_stereo(encoder_, value);
+               }
+
+               bool File::set_loose_mid_side_stereo(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_loose_mid_side_stereo(encoder_, value);
+               }
+
+               bool File::set_channels(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_channels(encoder_, value);
+               }
+
+               bool File::set_bits_per_sample(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_bits_per_sample(encoder_, value);
+               }
+
+               bool File::set_sample_rate(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_sample_rate(encoder_, value);
+               }
+
+               bool File::set_blocksize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_blocksize(encoder_, value);
+               }
+
+               bool File::set_max_lpc_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_max_lpc_order(encoder_, value);
+               }
+
+               bool File::set_qlp_coeff_precision(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_qlp_coeff_precision(encoder_, value);
+               }
+
+               bool File::set_do_qlp_coeff_prec_search(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_do_qlp_coeff_prec_search(encoder_, value);
+               }
+
+               bool File::set_do_escape_coding(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_do_escape_coding(encoder_, value);
+               }
+
+               bool File::set_do_exhaustive_model_search(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_do_exhaustive_model_search(encoder_, value);
+               }
+
+               bool File::set_min_residual_partition_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_min_residual_partition_order(encoder_, value);
+               }
+
+               bool File::set_max_residual_partition_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_max_residual_partition_order(encoder_, value);
+               }
+
+               bool File::set_rice_parameter_search_dist(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_rice_parameter_search_dist(encoder_, value);
+               }
+
+               bool File::set_total_samples_estimate(FLAC__uint64 value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_total_samples_estimate(encoder_, value);
+               }
+
+               bool File::set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_metadata(encoder_, metadata, num_blocks);
+               }
+
+               bool File::set_filename(const char *value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_set_filename(encoder_, value);
+               }
+
+               File::State File::get_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return State(::OggFLAC__file_encoder_get_state(encoder_));
+               }
+
+               SeekableStream::State File::get_seekable_stream_encoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return SeekableStream::State(::OggFLAC__file_encoder_get_seekable_stream_encoder_state(encoder_));
+               }
+
+               FLAC::Encoder::SeekableStream::State File::get_FLAC_seekable_stream_encoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Encoder::SeekableStream::State(::OggFLAC__file_encoder_get_FLAC_seekable_stream_encoder_state(encoder_));
+               }
+
+               FLAC::Encoder::Stream::State File::get_FLAC_stream_encoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Encoder::Stream::State(::OggFLAC__file_encoder_get_FLAC_stream_encoder_state(encoder_));
+               }
+
+               FLAC::Decoder::Stream::State File::get_verify_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::Stream::State(::OggFLAC__file_encoder_get_verify_decoder_state(encoder_));
+               }
+
+               void File::get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__file_encoder_get_verify_decoder_error_stats(encoder_, absolute_sample, frame_number, channel, sample, expected, got);
+               }
+
+               bool File::get_verify() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_verify(encoder_);
+               }
+
+               bool File::get_streamable_subset() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_streamable_subset(encoder_);
+               }
+
+               bool File::get_do_mid_side_stereo() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_do_mid_side_stereo(encoder_);
+               }
+
+               bool File::get_loose_mid_side_stereo() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_loose_mid_side_stereo(encoder_);
+               }
+
+               unsigned File::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_channels(encoder_);
+               }
+
+               unsigned File::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_bits_per_sample(encoder_);
+               }
+
+               unsigned File::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_sample_rate(encoder_);
+               }
+
+               unsigned File::get_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_blocksize(encoder_);
+               }
+
+               unsigned File::get_max_lpc_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_max_lpc_order(encoder_);
+               }
+
+               unsigned File::get_qlp_coeff_precision() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_qlp_coeff_precision(encoder_);
+               }
+
+               bool File::get_do_qlp_coeff_prec_search() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_do_qlp_coeff_prec_search(encoder_);
+               }
+
+               bool File::get_do_escape_coding() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_do_escape_coding(encoder_);
+               }
+
+               bool File::get_do_exhaustive_model_search() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_get_do_exhaustive_model_search(encoder_);
+               }
+
+               unsigned File::get_min_residual_partition_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_min_residual_partition_order(encoder_);
+               }
+
+               unsigned File::get_max_residual_partition_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_max_residual_partition_order(encoder_);
+               }
+
+               unsigned File::get_rice_parameter_search_dist() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_rice_parameter_search_dist(encoder_);
+               }
+
+               FLAC__uint64 File::get_total_samples_estimate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__file_encoder_get_total_samples_estimate(encoder_);
+               }
+
+               File::State File::init()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__file_encoder_set_progress_callback(encoder_, progress_callback_);
+                       ::OggFLAC__file_encoder_set_client_data(encoder_, (void*)this);
+                       return State(::OggFLAC__file_encoder_init(encoder_));
+               }
+
+               void File::finish()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__file_encoder_finish(encoder_);
+               }
+
+               bool File::process(const FLAC__int32 * const buffer[], unsigned samples)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_process(encoder_, buffer, samples);
+               }
+
+               bool File::process_interleaved(const FLAC__int32 buffer[], unsigned samples)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__file_encoder_process_interleaved(encoder_, buffer, samples);
+               }
+
+               void File::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
+               {
+                       (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
+               }
+
+               void File::progress_callback_(const ::OggFLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       File *instance = reinterpret_cast<File *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->progress_callback(bytes_written, samples_written, frames_written, total_frames_estimate);
+               }
+
+       };
+};
index 86aa879..1c13d34 100644 (file)
@@ -92,6 +92,22 @@ LINK32=link.exe
 # PROP Default_Filter "cpp"\r
 # Begin Source File\r
 \r
+SOURCE=.\file_decoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\file_encoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_decoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_encoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\stream_decoder.cpp\r
 # End Source File\r
 # Begin Source File\r
index 6178c25..0331571 100644 (file)
@@ -85,6 +85,22 @@ LIB32=link.exe -lib
 # PROP Default_Filter "cpp"\r
 # Begin Source File\r
 \r
+SOURCE=.\file_decoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\file_encoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_decoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_encoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\stream_decoder.cpp\r
 # End Source File\r
 # Begin Source File\r
diff --git a/src/libOggFLAC++/seekable_stream_decoder.cpp b/src/libOggFLAC++/seekable_stream_decoder.cpp
new file mode 100644 (file)
index 0000000..5d952aa
--- /dev/null
@@ -0,0 +1,287 @@
+/* libOggFLAC++ - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "OggFLAC++/decoder.h"
+#include "FLAC/assert.h"
+
+namespace OggFLAC {
+       namespace Decoder {
+
+               SeekableStream::SeekableStream():
+               decoder_(::OggFLAC__seekable_stream_decoder_new())
+               { }
+
+               SeekableStream::~SeekableStream()
+               {
+                       if(0 != decoder_) {
+                               (void) ::OggFLAC__seekable_stream_decoder_finish(decoder_);
+                               ::OggFLAC__seekable_stream_decoder_delete(decoder_);
+                       }
+               }
+
+               bool SeekableStream::is_valid() const
+               {
+                       return 0 != decoder_;
+               }
+
+               bool SeekableStream::set_serial_number(long value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_serial_number(decoder_, value);
+               }
+
+               bool SeekableStream::set_md5_checking(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_md5_checking(decoder_, value);
+               }
+
+               bool SeekableStream::set_metadata_respond(::FLAC__MetadataType type)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_metadata_respond(decoder_, type);
+               }
+
+               bool SeekableStream::set_metadata_respond_application(const FLAC__byte id[4])
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_metadata_respond_application(decoder_, id);
+               }
+
+               bool SeekableStream::set_metadata_respond_all()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder_);
+               }
+
+               bool SeekableStream::set_metadata_ignore(::FLAC__MetadataType type)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_metadata_ignore(decoder_, type);
+               }
+
+               bool SeekableStream::set_metadata_ignore_application(const FLAC__byte id[4])
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder_, id);
+               }
+
+               bool SeekableStream::set_metadata_ignore_all()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder_);
+               }
+
+               SeekableStream::State SeekableStream::get_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return State(::OggFLAC__seekable_stream_decoder_get_state(decoder_));
+               }
+
+               FLAC::Decoder::SeekableStream::State SeekableStream::get_FLAC_seekable_stream_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::SeekableStream::State(::OggFLAC__seekable_stream_decoder_get_FLAC_seekable_stream_decoder_state(decoder_));
+               }
+
+               FLAC::Decoder::Stream::State SeekableStream::get_FLAC_stream_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::Stream::State(::OggFLAC__seekable_stream_decoder_get_FLAC_stream_decoder_state(decoder_));
+               }
+
+               bool SeekableStream::get_md5_checking() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_get_md5_checking(decoder_);
+               }
+
+               unsigned SeekableStream::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_decoder_get_channels(decoder_);
+               }
+
+               ::FLAC__ChannelAssignment SeekableStream::get_channel_assignment() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_decoder_get_channel_assignment(decoder_);
+               }
+
+               unsigned SeekableStream::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_decoder_get_bits_per_sample(decoder_);
+               }
+
+               unsigned SeekableStream::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_decoder_get_sample_rate(decoder_);
+               }
+
+               unsigned SeekableStream::get_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_decoder_get_blocksize(decoder_);
+               }
+
+               SeekableStream::State SeekableStream::init()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__seekable_stream_decoder_set_read_callback(decoder_, read_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_seek_callback(decoder_, seek_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_tell_callback(decoder_, tell_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_length_callback(decoder_, length_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_eof_callback(decoder_, eof_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_write_callback(decoder_, write_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_metadata_callback(decoder_, metadata_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_error_callback(decoder_, error_callback_);
+                       ::OggFLAC__seekable_stream_decoder_set_client_data(decoder_, (void*)this);
+                       return State(::OggFLAC__seekable_stream_decoder_init(decoder_));
+               }
+
+               bool SeekableStream::finish()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_finish(decoder_);
+               }
+
+               bool SeekableStream::flush()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_flush(decoder_);
+               }
+
+               bool SeekableStream::reset()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_reset(decoder_);
+               }
+
+               bool SeekableStream::process_single()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_process_single(decoder_);
+               }
+
+               bool SeekableStream::process_until_end_of_metadata()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder_);
+               }
+
+               bool SeekableStream::process_until_end_of_stream()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_process_until_end_of_stream(decoder_);
+               }
+
+               bool SeekableStream::seek_absolute(FLAC__uint64 sample)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_decoder_seek_absolute(decoder_, sample);
+               }
+
+               ::FLAC__SeekableStreamDecoderReadStatus SeekableStream::read_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->read_callback(buffer, bytes);
+               }
+
+               ::FLAC__SeekableStreamDecoderSeekStatus SeekableStream::seek_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->seek_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__SeekableStreamDecoderTellStatus SeekableStream::tell_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->tell_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__SeekableStreamDecoderLengthStatus SeekableStream::length_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->length_callback(stream_length);
+               }
+
+               FLAC__bool SeekableStream::eof_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->eof_callback();
+               }
+
+               ::FLAC__StreamDecoderWriteStatus SeekableStream::write_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->write_callback(frame, buffer);
+               }
+
+               void SeekableStream::metadata_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->metadata_callback(metadata);
+               }
+
+               void SeekableStream::error_callback_(const ::OggFLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->error_callback(status);
+               }
+
+       };
+};
diff --git a/src/libOggFLAC++/seekable_stream_encoder.cpp b/src/libOggFLAC++/seekable_stream_encoder.cpp
new file mode 100644 (file)
index 0000000..2b6b8b0
--- /dev/null
@@ -0,0 +1,357 @@
+/* libOggFLAC++ - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "OggFLAC++/encoder.h"
+#include "FLAC/assert.h"
+
+namespace OggFLAC {
+       namespace Encoder {
+
+               SeekableStream::SeekableStream():
+               encoder_(::OggFLAC__seekable_stream_encoder_new())
+               { }
+
+               SeekableStream::~SeekableStream()
+               {
+                       if(0 != encoder_) {
+                               ::OggFLAC__seekable_stream_encoder_finish(encoder_);
+                               ::OggFLAC__seekable_stream_encoder_delete(encoder_);
+                       }
+               }
+
+               bool SeekableStream::set_serial_number(long value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_serial_number(encoder_, value);
+               }
+
+               bool SeekableStream::is_valid() const
+               {
+                       return 0 != encoder_;
+               }
+
+               bool SeekableStream::set_verify(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_verify(encoder_, value);
+               }
+
+               bool SeekableStream::set_streamable_subset(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_streamable_subset(encoder_, value);
+               }
+
+               bool SeekableStream::set_do_mid_side_stereo(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder_, value);
+               }
+
+               bool SeekableStream::set_loose_mid_side_stereo(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder_, value);
+               }
+
+               bool SeekableStream::set_channels(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_channels(encoder_, value);
+               }
+
+               bool SeekableStream::set_bits_per_sample(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_bits_per_sample(encoder_, value);
+               }
+
+               bool SeekableStream::set_sample_rate(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_sample_rate(encoder_, value);
+               }
+
+               bool SeekableStream::set_blocksize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_blocksize(encoder_, value);
+               }
+
+               bool SeekableStream::set_max_lpc_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_max_lpc_order(encoder_, value);
+               }
+
+               bool SeekableStream::set_qlp_coeff_precision(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder_, value);
+               }
+
+               bool SeekableStream::set_do_qlp_coeff_prec_search(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder_, value);
+               }
+
+               bool SeekableStream::set_do_escape_coding(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_do_escape_coding(encoder_, value);
+               }
+
+               bool SeekableStream::set_do_exhaustive_model_search(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder_, value);
+               }
+
+               bool SeekableStream::set_min_residual_partition_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder_, value);
+               }
+
+               bool SeekableStream::set_max_residual_partition_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder_, value);
+               }
+
+               bool SeekableStream::set_rice_parameter_search_dist(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder_, value);
+               }
+
+               bool SeekableStream::set_total_samples_estimate(FLAC__uint64 value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_total_samples_estimate(encoder_, value);
+               }
+
+               bool SeekableStream::set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_set_metadata(encoder_, metadata, num_blocks);
+               }
+
+               SeekableStream::State SeekableStream::get_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return State(::OggFLAC__seekable_stream_encoder_get_state(encoder_));
+               }
+
+               FLAC::Encoder::SeekableStream::State SeekableStream::get_FLAC_seekable_stream_encoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Encoder::SeekableStream::State(::OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state(encoder_));
+               }
+
+               FLAC::Encoder::Stream::State SeekableStream::get_FLAC_stream_encoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Encoder::Stream::State(::OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(encoder_));
+               }
+
+               FLAC::Decoder::Stream::State SeekableStream::get_verify_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return FLAC::Decoder::Stream::State(::OggFLAC__seekable_stream_encoder_get_verify_decoder_state(encoder_));
+               }
+
+               void SeekableStream::get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder_, absolute_sample, frame_number, channel, sample, expected, got);
+               }
+
+               bool SeekableStream::get_verify() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_verify(encoder_);
+               }
+
+               bool SeekableStream::get_streamable_subset() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_streamable_subset(encoder_);
+               }
+
+               bool SeekableStream::get_do_mid_side_stereo() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder_);
+               }
+
+               bool SeekableStream::get_loose_mid_side_stereo() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder_);
+               }
+
+               unsigned SeekableStream::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_channels(encoder_);
+               }
+
+               unsigned SeekableStream::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_bits_per_sample(encoder_);
+               }
+
+               unsigned SeekableStream::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_sample_rate(encoder_);
+               }
+
+               unsigned SeekableStream::get_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_blocksize(encoder_);
+               }
+
+               unsigned SeekableStream::get_max_lpc_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_max_lpc_order(encoder_);
+               }
+
+               unsigned SeekableStream::get_qlp_coeff_precision() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder_);
+               }
+
+               bool SeekableStream::get_do_qlp_coeff_prec_search() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder_);
+               }
+
+               bool SeekableStream::get_do_escape_coding() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_do_escape_coding(encoder_);
+               }
+
+               bool SeekableStream::get_do_exhaustive_model_search() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder_);
+               }
+
+               unsigned SeekableStream::get_min_residual_partition_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder_);
+               }
+
+               unsigned SeekableStream::get_max_residual_partition_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder_);
+               }
+
+               unsigned SeekableStream::get_rice_parameter_search_dist() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder_);
+               }
+
+               FLAC__uint64 SeekableStream::get_total_samples_estimate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::OggFLAC__seekable_stream_encoder_get_total_samples_estimate(encoder_);
+               }
+
+               SeekableStream::State SeekableStream::init()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__seekable_stream_encoder_set_seek_callback(encoder_, seek_callback_);
+                       ::OggFLAC__seekable_stream_encoder_set_tell_callback(encoder_, tell_callback_);
+                       ::OggFLAC__seekable_stream_encoder_set_write_callback(encoder_, write_callback_);
+                       ::OggFLAC__seekable_stream_encoder_set_client_data(encoder_, (void*)this);
+                       return State(::OggFLAC__seekable_stream_encoder_init(encoder_));
+               }
+
+               void SeekableStream::finish()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::OggFLAC__seekable_stream_encoder_finish(encoder_);
+               }
+
+               bool SeekableStream::process(const FLAC__int32 * const buffer[], unsigned samples)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_process(encoder_, buffer, samples);
+               }
+
+               bool SeekableStream::process_interleaved(const FLAC__int32 buffer[], unsigned samples)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::OggFLAC__seekable_stream_encoder_process_interleaved(encoder_, buffer, samples);
+               }
+
+               ::FLAC__SeekableStreamEncoderSeekStatus SeekableStream::seek_callback_(const ::OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->seek_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__SeekableStreamEncoderTellStatus SeekableStream::tell_callback_(const ::OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->tell_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__StreamEncoderWriteStatus SeekableStream::write_callback_(const ::OggFLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->write_callback(buffer, bytes, samples, current_frame);
+               }
+
+       };
+};
index 6fa7211..2397610 100644 (file)
@@ -50,5 +50,11 @@ libOggFLAC_la_LIBADD = @OGG_LIBS@ ../libFLAC/libFLAC.la
 libOggFLAC_la_LDFLAGS = -version-info 1:2:0
 
 libOggFLAC_la_SOURCES = \
+       file_decoder.c \
+       file_encoder.c \
+       ogg_decoder_aspect.c \
+       ogg_encoder_aspect.c \
+       seekable_stream_decoder.c \
+       seekable_stream_encoder.c \
        stream_decoder.c \
        stream_encoder.c
index ccc5dc5..2f4e9a1 100644 (file)
@@ -48,6 +48,12 @@ INCLUDES = -I./include -I$(topdir)/include -I$(HOME)/local/include
 DEBUG_CFLAGS = 
 
 SRCS_C = \
+       file_decoder.c \
+       file_encoder.c \
+       ogg_decoder_aspect.c \
+       ogg_encoder_aspect.c \
+       seekable_stream_decoder.c \
+       seekable_stream_encoder.c \
        stream_decoder.c \
        stream_encoder.c
 
diff --git a/src/libOggFLAC/file_encoder.c b/src/libOggFLAC/file_encoder.c
new file mode 100644 (file)
index 0000000..da465d2
--- /dev/null
@@ -0,0 +1,783 @@
+/* libOggFLAC - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for strlen(), strcpy() */
+#include "FLAC/assert.h"
+#include "OggFLAC/seekable_stream_encoder.h"
+#include "protected/file_encoder.h"
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+/* unpublished debug routines */
+extern FLAC__bool OggFLAC__seekable_stream_encoder_disable_constant_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool OggFLAC__seekable_stream_encoder_disable_fixed_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool OggFLAC__seekable_stream_encoder_disable_verbatim_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+static void set_defaults_(OggFLAC__FileEncoder *encoder);
+static FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__SeekableStreamEncoderTellStatus tell_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderWriteStatus write_callback_(const OggFLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct OggFLAC__FileEncoderPrivate {
+       OggFLAC__FileEncoderProgressCallback progress_callback;
+       void *client_data;
+       char *filename;
+       FLAC__uint64 bytes_written;
+       FLAC__uint64 samples_written;
+       unsigned total_frames_estimate;
+       OggFLAC__SeekableStreamEncoder *seekable_stream_encoder;
+       FILE *file;
+} OggFLAC__FileEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+OggFLAC_API const char * const OggFLAC__FileEncoderStateString[] = {
+       "OggFLAC__FILE_ENCODER_OK",
+       "OggFLAC__FILE_ENCODER_NO_FILENAME",
+       "OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR",
+       "OggFLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING",
+       "OggFLAC__FILE_ENCODER_ERROR_OPENING_FILE",
+       "OggFLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR",
+       "OggFLAC__FILE_ENCODER_ALREADY_INITIALIZED",
+       "OggFLAC__FILE_ENCODER_UNINITIALIZED"
+};
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+OggFLAC_API OggFLAC__FileEncoder *OggFLAC__file_encoder_new()
+{
+       OggFLAC__FileEncoder *encoder;
+
+       FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+       encoder = (OggFLAC__FileEncoder*)calloc(1, sizeof(OggFLAC__FileEncoder));
+       if(encoder == 0) {
+               return 0;
+       }
+
+       encoder->protected_ = (OggFLAC__FileEncoderProtected*)calloc(1, sizeof(OggFLAC__FileEncoderProtected));
+       if(encoder->protected_ == 0) {
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_ = (OggFLAC__FileEncoderPrivate*)calloc(1, sizeof(OggFLAC__FileEncoderPrivate));
+       if(encoder->private_ == 0) {
+               free(encoder->protected_);
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_->seekable_stream_encoder = OggFLAC__seekable_stream_encoder_new();
+       if(0 == encoder->private_->seekable_stream_encoder) {
+               free(encoder->private_);
+               free(encoder->protected_);
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_->file = 0;
+
+       set_defaults_(encoder);
+
+       encoder->protected_->state = OggFLAC__FILE_ENCODER_UNINITIALIZED;
+
+       return encoder;
+}
+
+OggFLAC_API void OggFLAC__file_encoder_delete(OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+
+       (void)OggFLAC__file_encoder_finish(encoder);
+
+       OggFLAC__seekable_stream_encoder_delete(encoder->private_->seekable_stream_encoder);
+
+       free(encoder->private_);
+       free(encoder->protected_);
+       free(encoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+OggFLAC_API OggFLAC__FileEncoderState OggFLAC__file_encoder_init(OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return encoder->protected_->state = OggFLAC__FILE_ENCODER_ALREADY_INITIALIZED;
+
+       if(0 == encoder->private_->filename)
+               return encoder->protected_->state = OggFLAC__FILE_ENCODER_NO_FILENAME;
+
+       encoder->private_->file = fopen(encoder->private_->filename, "w+b");
+
+       if(encoder->private_->file == 0)
+               return encoder->protected_->state = OggFLAC__FILE_ENCODER_ERROR_OPENING_FILE;
+
+       encoder->private_->bytes_written = 0;
+       encoder->private_->samples_written = 0;
+
+       OggFLAC__seekable_stream_encoder_set_seek_callback(encoder->private_->seekable_stream_encoder, seek_callback_);
+       OggFLAC__seekable_stream_encoder_set_tell_callback(encoder->private_->seekable_stream_encoder, tell_callback_);
+       OggFLAC__seekable_stream_encoder_set_write_callback(encoder->private_->seekable_stream_encoder, write_callback_);
+       OggFLAC__seekable_stream_encoder_set_client_data(encoder->private_->seekable_stream_encoder, encoder);
+
+       if(OggFLAC__seekable_stream_encoder_init(encoder->private_->seekable_stream_encoder) != OggFLAC__SEEKABLE_STREAM_ENCODER_OK)
+               return encoder->protected_->state = OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
+
+       {
+               unsigned blocksize = OggFLAC__file_encoder_get_blocksize(encoder);
+
+               FLAC__ASSERT(blocksize != 0);
+               encoder->private_->total_frames_estimate = (unsigned)((OggFLAC__file_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
+       }
+
+       return encoder->protected_->state = OggFLAC__FILE_ENCODER_OK;
+}
+
+OggFLAC_API void OggFLAC__file_encoder_finish(OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+
+       if(encoder->protected_->state == OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return;
+
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+
+       /* OggFLAC__seekable_stream_encoder_finish() might write data so we must close the file after it. */
+
+       OggFLAC__seekable_stream_encoder_finish(encoder->private_->seekable_stream_encoder);
+
+       if(0 != encoder->private_->file) {
+               fclose(encoder->private_->file);
+               encoder->private_->file = 0;
+       }
+
+       if(0 != encoder->private_->filename) {
+               free(encoder->private_->filename);
+               encoder->private_->filename = 0;
+       }
+
+       set_defaults_(encoder);
+
+       encoder->protected_->state = OggFLAC__FILE_ENCODER_UNINITIALIZED;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_serial_number(OggFLAC__FileEncoder *encoder, long serial_number)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_serial_number(encoder->private_->seekable_stream_encoder, serial_number);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_verify(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_verify(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_streamable_subset(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_streamable_subset(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_mid_side_stereo(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_loose_mid_side_stereo(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_channels(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_channels(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_bits_per_sample(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_bits_per_sample(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_sample_rate(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_sample_rate(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_blocksize(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_blocksize(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_max_lpc_order(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_max_lpc_order(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_qlp_coeff_precision(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_qlp_coeff_prec_search(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_escape_coding(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_do_escape_coding(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_do_exhaustive_model_search(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_min_residual_partition_order(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_max_residual_partition_order(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_rice_parameter_search_dist(OggFLAC__FileEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_total_samples_estimate(OggFLAC__FileEncoder *encoder, FLAC__uint64 value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_total_samples_estimate(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_metadata(OggFLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_set_metadata(encoder->private_->seekable_stream_encoder, metadata, num_blocks);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_filename(OggFLAC__FileEncoder *encoder, const char *value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != value);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       if(0 != encoder->private_->filename) {
+               free(encoder->private_->filename);
+               encoder->private_->filename = 0;
+       }
+       if(0 == (encoder->private_->filename = (char*)malloc(strlen(value)+1))) {
+               encoder->protected_->state = OggFLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       strcpy(encoder->private_->filename, value);
+       return true;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_progress_callback(OggFLAC__FileEncoder *encoder, OggFLAC__FileEncoderProgressCallback value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->progress_callback = value;
+       return true;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_client_data(OggFLAC__FileEncoder *encoder, void *value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->client_data = value;
+       return true;
+}
+
+/*
+ * These three functions are not static, but not publically exposed in
+ * include/OggFLAC/ either.  They are used by the test suite.
+ */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_disable_constant_subframes(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_disable_constant_subframes(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_disable_fixed_subframes(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_disable_fixed_subframes(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_disable_verbatim_subframes(OggFLAC__FileEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED)
+               return false;
+       return OggFLAC__seekable_stream_encoder_disable_verbatim_subframes(encoder->private_->seekable_stream_encoder, value);
+}
+
+OggFLAC_API OggFLAC__FileEncoderState OggFLAC__file_encoder_get_state(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->state;
+}
+
+OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__file_encoder_get_seekable_stream_encoder_state(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_state(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__SeekableStreamEncoderState OggFLAC__file_encoder_get_FLAC_seekable_stream_encoder_state(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__StreamEncoderState OggFLAC__file_encoder_get_FLAC_stream_encoder_state(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__StreamDecoderState OggFLAC__file_encoder_get_verify_decoder_state(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_verify_decoder_state(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API const char *OggFLAC__file_encoder_get_resolved_state_string(const OggFLAC__FileEncoder *encoder)
+{
+       if(encoder->protected_->state != OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR)
+               return OggFLAC__FileEncoderStateString[encoder->protected_->state];
+       else
+               return OggFLAC__seekable_stream_encoder_get_resolved_state_string(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API void OggFLAC__file_encoder_get_verify_decoder_error_stats(const OggFLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder->private_->seekable_stream_encoder, absolute_sample, frame_number, channel, sample, expected, got);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_verify(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_verify(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_streamable_subset(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_streamable_subset(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_mid_side_stereo(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_loose_mid_side_stereo(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_channels(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_channels(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_bits_per_sample(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_bits_per_sample(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_sample_rate(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_sample_rate(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_blocksize(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_blocksize(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_max_lpc_order(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_max_lpc_order(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_qlp_coeff_precision(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_escape_coding(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_do_escape_coding(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_get_do_exhaustive_model_search(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_min_residual_partition_order(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_max_residual_partition_order(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__file_encoder_get_rice_parameter_search_dist(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__uint64 OggFLAC__file_encoder_get_total_samples_estimate(const OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       return OggFLAC__seekable_stream_encoder_get_total_samples_estimate(encoder->private_->seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_process(OggFLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       if(!OggFLAC__seekable_stream_encoder_process(encoder->private_->seekable_stream_encoder, buffer, samples)) {
+               encoder->protected_->state = OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
+               return false;
+       }
+       else
+               return true;
+}
+
+/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */
+OggFLAC_API FLAC__bool OggFLAC__file_encoder_process_interleaved(OggFLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       if(!OggFLAC__seekable_stream_encoder_process_interleaved(encoder->private_->seekable_stream_encoder, buffer, samples)) {
+               encoder->protected_->state = OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
+               return false;
+       }
+       else
+               return true;
+}
+
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(OggFLAC__FileEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+
+       encoder->private_->progress_callback = 0;
+       encoder->private_->client_data = 0;
+       encoder->private_->total_frames_estimate = 0;
+       encoder->private_->filename = 0;
+}
+
+FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       OggFLAC__FileEncoder *file_encoder = (OggFLAC__FileEncoder*)client_data;
+
+       (void)encoder;
+
+       FLAC__ASSERT(0 != file_encoder);
+
+       if(fseek(file_encoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0)
+               return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR;
+       else
+               return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+FLAC__SeekableStreamEncoderTellStatus tell_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       OggFLAC__FileEncoder *file_encoder = (OggFLAC__FileEncoder*)client_data;
+       long offset;
+
+       (void)encoder;
+
+       FLAC__ASSERT(0 != file_encoder);
+
+       offset = ftell(file_encoder->private_->file);
+
+       if(offset < 0) {
+               return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR;
+       }
+       else {
+               *absolute_byte_offset = (FLAC__uint64)offset;
+               return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
+       }
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+FLAC__StreamEncoderWriteStatus write_callback_(const OggFLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+       OggFLAC__FileEncoder *file_encoder = (OggFLAC__FileEncoder*)client_data;
+
+       (void)encoder, (void)samples, (void)current_frame;
+
+       FLAC__ASSERT(0 != file_encoder);
+
+       if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, file_encoder->private_->file) == bytes) {
+               file_encoder->private_->bytes_written += bytes;
+               file_encoder->private_->samples_written += samples;
+               if(0 != file_encoder->private_->progress_callback && samples > 0)
+                       file_encoder->private_->progress_callback(file_encoder, file_encoder->private_->bytes_written, file_encoder->private_->samples_written, current_frame+1, file_encoder->private_->total_frames_estimate, file_encoder->private_->client_data);
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+       }
+       else
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+}
index 2235acc..fbe099f 100644 (file)
@@ -31,6 +31,8 @@
 noinst_HEADERS = \
        all.h \
        file_decoder.h \
+       file_encoder.h \
        seekable_stream_decoder.h \
+       seekable_stream_encoder.h \
        stream_decoder.h \
        stream_encoder.h
index 1e25c2b..7d7e2b0 100644 (file)
@@ -33,7 +33,9 @@
 #define OggFLAC__PROTECTED__ALL_H
 
 #include "file_decoder.h"
+#include "file_encoder.h"
 #include "seekable_stream_decoder.h"
+#include "seekable_stream_encoder.h"
 #include "stream_decoder.h"
 #include "stream_encoder.h"
 
diff --git a/src/libOggFLAC/include/protected/file_encoder.h b/src/libOggFLAC/include/protected/file_encoder.h
new file mode 100644 (file)
index 0000000..005a865
--- /dev/null
@@ -0,0 +1,41 @@
+/* libOggFLAC - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OggFLAC__PROTECTED__FILE_ENCODER_H
+#define OggFLAC__PROTECTED__FILE_ENCODER_H
+
+#include "OggFLAC/file_encoder.h"
+
+typedef struct OggFLAC__FileEncoderProtected {
+       OggFLAC__FileEncoderState state;
+} OggFLAC__FileEncoderProtected;
+
+#endif
diff --git a/src/libOggFLAC/include/protected/seekable_stream_encoder.h b/src/libOggFLAC/include/protected/seekable_stream_encoder.h
new file mode 100644 (file)
index 0000000..c869399
--- /dev/null
@@ -0,0 +1,43 @@
+/* libOggFLAC - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OggFLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H
+#define OggFLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H
+
+#include "OggFLAC/seekable_stream_encoder.h"
+#include "private/ogg_encoder_aspect.h"
+
+typedef struct OggFLAC__SeekableStreamEncoderProtected {
+       OggFLAC__SeekableStreamEncoderState state;
+       OggFLAC__OggEncoderAspect ogg_encoder_aspect;
+} OggFLAC__SeekableStreamEncoderProtected;
+
+#endif
index 7632bde..d77563c 100644 (file)
@@ -92,6 +92,30 @@ LINK32=link.exe
 # PROP Default_Filter "c"\r
 # Begin Source File\r
 \r
+SOURCE=.\file_decoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\file_encoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_decoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_encoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_decoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_encoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\stream_decoder.c\r
 # End Source File\r
 # Begin Source File\r
@@ -102,6 +126,18 @@ SOURCE=.\stream_encoder.c
 # Begin Group "Private Header Files"\r
 \r
 # PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_decoder_aspect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_encoder_aspect.h\r
+# End Source File\r
 # End Group\r
 # Begin Group "Protected Header Files"\r
 \r
@@ -112,6 +148,22 @@ SOURCE=.\include\protected\all.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\include\protected\file_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\file_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\seekable_stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\seekable_stream_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\include\protected\stream_decoder.h\r
 # End Source File\r
 # Begin Source File\r
@@ -132,6 +184,22 @@ SOURCE=..\..\include\OggFLAC\export.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\..\include\OggFLAC\file_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\OggFLAC\file_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\OggFLAC\seekable_stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\OggFLAC\seekable_stream_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\..\include\OggFLAC\stream_decoder.h\r
 # End Source File\r
 # Begin Source File\r
index cb2b805..db06fc7 100644 (file)
@@ -85,6 +85,30 @@ LIB32=link.exe -lib
 # PROP Default_Filter "c"\r
 # Begin Source File\r
 \r
+SOURCE=.\file_decoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\file_encoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_decoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_encoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_decoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seekable_stream_encoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\stream_decoder.c\r
 # End Source File\r
 # Begin Source File\r
@@ -95,6 +119,18 @@ SOURCE=.\stream_encoder.c
 # Begin Group "Private Header Files"\r
 \r
 # PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_decoder_aspect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_encoder_aspect.h\r
+# End Source File\r
 # End Group\r
 # Begin Group "Protected Header Files"\r
 \r
@@ -105,6 +141,22 @@ SOURCE=.\include\protected\all.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\include\protected\file_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\file_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\seekable_stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\seekable_stream_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\include\protected\stream_decoder.h\r
 # End Source File\r
 # Begin Source File\r
@@ -125,6 +177,22 @@ SOURCE=..\..\include\OggFLAC\export.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\..\include\OggFLAC\file_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\OggFLAC\file_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\OggFLAC\seekable_stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\OggFLAC\seekable_stream_encoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\..\include\OggFLAC\stream_decoder.h\r
 # End Source File\r
 # Begin Source File\r
diff --git a/src/libOggFLAC/seekable_stream_encoder.c b/src/libOggFLAC/seekable_stream_encoder.c
new file mode 100644 (file)
index 0000000..515c004
--- /dev/null
@@ -0,0 +1,732 @@
+/* libOggFLAC - Free Lossless Audio Codec + Ogg library
+ * Copyright (C) 2002,2003  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for calloc() */
+#include "FLAC/assert.h"
+#include "OggFLAC/seekable_stream_encoder.h"
+#include "protected/seekable_stream_encoder.h"
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+/* unpublished debug routines */
+extern FLAC__bool FLAC__seekable_stream_encoder_disable_constant_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__seekable_stream_encoder_disable_fixed_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+static void set_defaults_(OggFLAC__SeekableStreamEncoder *encoder);
+static FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct OggFLAC__SeekableStreamEncoderPrivate {
+       OggFLAC__SeekableStreamEncoderSeekCallback seek_callback;
+       OggFLAC__SeekableStreamEncoderTellCallback tell_callback;
+       OggFLAC__SeekableStreamEncoderWriteCallback write_callback;
+       void *client_data;
+       FLAC__SeekableStreamEncoder *FLAC_seekable_stream_encoder;
+} OggFLAC__SeekableStreamEncoderPrivate;
+
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+OggFLAC_API const char * const OggFLAC__SeekableStreamEncoderStateString[] = {
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_OK",
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR",
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR",
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK",
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR",
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED",
+       "OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED"
+};
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ */
+OggFLAC_API OggFLAC__SeekableStreamEncoder *OggFLAC__seekable_stream_encoder_new()
+{
+       OggFLAC__SeekableStreamEncoder *encoder;
+
+       encoder = (OggFLAC__SeekableStreamEncoder*)calloc(1, sizeof(OggFLAC__SeekableStreamEncoder));
+       if(encoder == 0) {
+               return 0;
+       }
+
+       encoder->protected_ = (OggFLAC__SeekableStreamEncoderProtected*)calloc(1, sizeof(OggFLAC__SeekableStreamEncoderProtected));
+       if(encoder->protected_ == 0) {
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_ = (OggFLAC__SeekableStreamEncoderPrivate*)calloc(1, sizeof(OggFLAC__SeekableStreamEncoderPrivate));
+       if(encoder->private_ == 0) {
+               free(encoder->protected_);
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_->FLAC_seekable_stream_encoder = FLAC__seekable_stream_encoder_new();
+       if(0 == encoder->private_->FLAC_seekable_stream_encoder) {
+               free(encoder->private_);
+               free(encoder->protected_);
+               free(encoder);
+               return 0;
+       }
+
+       set_defaults_(encoder);
+
+       encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED;
+
+       return encoder;
+}
+
+OggFLAC_API void OggFLAC__seekable_stream_encoder_delete(OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+
+       (void)OggFLAC__seekable_stream_encoder_finish(encoder);
+
+       FLAC__seekable_stream_encoder_delete(encoder->private_->FLAC_seekable_stream_encoder);
+
+       free(encoder->private_);
+       free(encoder->protected_);
+       free(encoder);
+}
+
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_init(OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED;
+
+       if(0 == encoder->private_->seek_callback || 0 == encoder->private_->tell_callback || 0 == encoder->private_->write_callback)
+               return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK;
+
+       if(!OggFLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect))
+                       return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
+
+       FLAC__seekable_stream_encoder_set_seek_callback(encoder->private_->FLAC_seekable_stream_encoder, seek_callback_);
+       FLAC__seekable_stream_encoder_set_tell_callback(encoder->private_->FLAC_seekable_stream_encoder, tell_callback_);
+       FLAC__seekable_stream_encoder_set_write_callback(encoder->private_->FLAC_seekable_stream_encoder, write_callback_);
+       FLAC__seekable_stream_encoder_set_client_data(encoder->private_->FLAC_seekable_stream_encoder, encoder);
+
+       if(FLAC__seekable_stream_encoder_init(encoder->private_->FLAC_seekable_stream_encoder) != FLAC__SEEKABLE_STREAM_ENCODER_OK)
+               return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR;
+
+       return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OK;
+}
+
+OggFLAC_API void OggFLAC__seekable_stream_encoder_finish(OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+
+       if(encoder->protected_->state == OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return;
+
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+
+       FLAC__seekable_stream_encoder_finish(encoder->private_->FLAC_seekable_stream_encoder);
+
+       OggFLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
+
+       set_defaults_(encoder);
+
+       encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_serial_number(OggFLAC__SeekableStreamEncoder *encoder, long value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       OggFLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
+       return true;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_verify(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_verify(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_streamable_subset(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_streamable_subset(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_channels(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_channels(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_bits_per_sample(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_bits_per_sample(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_sample_rate(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_sample_rate(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_blocksize(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_blocksize(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_lpc_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_max_lpc_order(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_escape_coding(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_do_escape_coding(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_min_residual_partition_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_residual_partition_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_total_samples_estimate(OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_total_samples_estimate(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_metadata(OggFLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_->FLAC_seekable_stream_encoder);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_set_metadata(encoder->private_->FLAC_seekable_stream_encoder, metadata, num_blocks);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_seek_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderSeekCallback value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != value);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->seek_callback = value;
+       return true;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_tell_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderTellCallback value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != value);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->tell_callback = value;
+       return true;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_write_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderWriteCallback value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != value);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->write_callback = value;
+       return true;
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_client_data(OggFLAC__SeekableStreamEncoder *encoder, void *value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->client_data = value;
+       return true;
+}
+
+/*
+ * These three functions are not static, but not publically exposed in
+ * include/FLAC/ either.  They are used by the test suite.
+ */
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_disable_constant_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_disable_constant_subframes(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_disable_fixed_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_disable_fixed_subframes(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_disable_verbatim_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       return FLAC__seekable_stream_encoder_disable_verbatim_subframes(encoder->private_->FLAC_seekable_stream_encoder, value);
+}
+
+OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_get_state(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->state;
+}
+
+OggFLAC_API FLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_state(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__StreamEncoderState OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_stream_encoder_state(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__StreamDecoderState OggFLAC__seekable_stream_encoder_get_verify_decoder_state(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_verify_decoder_state(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API const char *OggFLAC__seekable_stream_encoder_get_resolved_state_string(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR)
+               return OggFLAC__SeekableStreamEncoderStateString[encoder->protected_->state];
+       else
+               return FLAC__seekable_stream_encoder_get_resolved_state_string(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API void OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder->private_->FLAC_seekable_stream_encoder, absolute_sample, frame_number, channel, sample, expected, got);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_verify(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_verify(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_streamable_subset(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_streamable_subset(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_channels(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_channels(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_bits_per_sample(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_bits_per_sample(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_sample_rate(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_sample_rate(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_blocksize(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_blocksize(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_lpc_order(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_max_lpc_order(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_escape_coding(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_do_escape_coding(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__uint64 OggFLAC__seekable_stream_encoder_get_total_samples_estimate(const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_get_total_samples_estimate(encoder->private_->FLAC_seekable_stream_encoder);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_process(encoder->private_->FLAC_seekable_stream_encoder, buffer, samples);
+}
+
+OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process_interleaved(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return FLAC__seekable_stream_encoder_process_interleaved(encoder->private_->FLAC_seekable_stream_encoder, buffer, samples);
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(OggFLAC__SeekableStreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+
+       encoder->private_->seek_callback = 0;
+       encoder->private_->tell_callback = 0;
+       encoder->private_->write_callback = 0;
+       encoder->private_->client_data = 0;
+       OggFLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
+}
+
+FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *unused, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
+
+       (void)unused;
+       FLAC__ASSERT(encoder->private_->FLAC_seekable_stream_encoder == unused);
+
+       return encoder->private_->seek_callback(encoder, absolute_byte_offset, encoder->private_->client_data);
+}
+
+FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *unused, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
+
+       (void)unused;
+       FLAC__ASSERT(encoder->private_->FLAC_seekable_stream_encoder == unused);
+
+       return encoder->private_->tell_callback(encoder, absolute_byte_offset, encoder->private_->client_data);
+}
+
+FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *unused, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+       OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
+       const FLAC__uint64 total_samples_estimate = FLAC__seekable_stream_encoder_get_total_samples_estimate(encoder->private_->FLAC_seekable_stream_encoder);
+
+       (void)unused;
+       FLAC__ASSERT(encoder->private_->FLAC_seekable_stream_encoder == unused);
+
+       return OggFLAC__ogg_encoder_aspect_write_callback_wrapper(&encoder->protected_->ogg_encoder_aspect, total_samples_estimate, buffer, bytes, samples, current_frame, (OggFLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, encoder, encoder->private_->client_data);
+}
index 236a244..32020c2 100644 (file)
@@ -795,16 +795,1402 @@ static bool test_stream_decoder()
        return true;
 }
 
+class SeekableStreamDecoder : public OggFLAC::Decoder::SeekableStream, public DecoderCommon {
+public:
+       SeekableStreamDecoder(): OggFLAC::Decoder::SeekableStream(), DecoderCommon() { }
+       ~SeekableStreamDecoder() { }
+
+       // from OggFLAC::Decoder::SeekableStream
+       ::FLAC__SeekableStreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes);
+       ::FLAC__SeekableStreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+       ::FLAC__SeekableStreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+       ::FLAC__SeekableStreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length);
+       bool eof_callback();
+       ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+       void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+       void error_callback(::FLAC__StreamDecoderErrorStatus status);
+
+       bool die(const char *msg = 0) const;
+
+       bool test_respond();
+};
+
+::FLAC__SeekableStreamDecoderReadStatus SeekableStreamDecoder::read_callback(FLAC__byte buffer[], unsigned *bytes)
+{
+       switch(common_read_callback_(buffer, bytes)) {
+               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;
+       }
+}
+
+::FLAC__SeekableStreamDecoderSeekStatus SeekableStreamDecoder::seek_callback(FLAC__uint64 absolute_byte_offset)
+{
+       if(error_occurred_)
+               return ::FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+
+       if(::fseek(file_, (long)absolute_byte_offset, SEEK_SET) < 0) {
+               error_occurred_ = true;
+               return ::FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+       }
+
+       return ::FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+::FLAC__SeekableStreamDecoderTellStatus SeekableStreamDecoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+       if(error_occurred_)
+               return ::FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+
+       long offset = ::ftell(file_);
+       *absolute_byte_offset = (FLAC__uint64)offset;
+
+       if(offset < 0) {
+               error_occurred_ = true;
+               return ::FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+       }
+
+       return ::FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+}
+
+::FLAC__SeekableStreamDecoderLengthStatus SeekableStreamDecoder::length_callback(FLAC__uint64 *stream_length)
+{
+       if(error_occurred_)
+               return ::FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+       *stream_length = (FLAC__uint64)oggflacfilesize_;
+       return ::FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+bool SeekableStreamDecoder::eof_callback()
+{
+       if(error_occurred_)
+               return true;
+
+       return (bool)feof(file_);
+}
+
+::FLAC__StreamDecoderWriteStatus SeekableStreamDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       (void)buffer;
+
+       return common_write_callback_(frame);
+}
+
+void SeekableStreamDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+       common_metadata_callback_(metadata);
+}
+
+void SeekableStreamDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+       common_error_callback_(status);
+}
+
+bool SeekableStreamDecoder::die(const char *msg) const
+{
+       State state = get_state();
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)((::OggFLAC__SeekableStreamDecoderState)state), state.as_cstring());
+       if(state == ::OggFLAC__SEEKABLE_STREAM_DECODER_FLAC_SEEKABLE_STREAM_DECODER_ERROR) {
+               FLAC::Decoder::SeekableStream::State state_ = get_FLAC_seekable_stream_decoder_state();
+               printf("      FLAC seekable stream decoder state = %u (%s)\n", (unsigned)((::FLAC__SeekableStreamDecoderState)state_), state_.as_cstring());
+               if(state_ == ::FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR) {
+                       FLAC::Decoder::Stream::State state__ = get_FLAC_stream_decoder_state();
+                       printf("      FLAC stream decoder state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state__), state__.as_cstring());
+               }
+       }
+
+       return false;
+}
+
+bool SeekableStreamDecoder::test_respond()
+{
+       if(!set_md5_checking(true)) {
+               printf("FAILED at set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       printf("testing init()... ");
+       if(init() != ::OggFLAC__SEEKABLE_STREAM_DECODER_OK)
+               return die();
+       printf("OK\n");
+
+       current_metadata_number_ = 0;
+
+       if(::fseek(file_, 0, SEEK_SET) < 0) {
+               printf("FAILED rewinding input, errno = %d\n", errno);
+               return false;
+       }
+
+       printf("testing process_until_end_of_stream()... ");
+       if(!process_until_end_of_stream()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::OggFLAC__SeekableStreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       finish();
+       printf("OK\n");
+
+       return true;
+}
+
+static bool test_seekable_stream_decoder()
+{
+       SeekableStreamDecoder *decoder;
+
+       printf("\n+++ libOggFLAC++ unit test: OggFLAC::Decoder::SeekableStream\n\n");
+
+       //
+       // test new -> delete
+       //
+       printf("allocating decoder instance... ");
+       decoder = new SeekableStreamDecoder();
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       //
+       // test new -> init -> delete
+       //
+       printf("allocating decoder instance... ");
+       decoder = new SeekableStreamDecoder();
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing init()... ");
+       if(decoder->init() != ::OggFLAC__SEEKABLE_STREAM_DECODER_OK)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       //
+       // test normal usage
+       //
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("allocating decoder instance... ");
+       decoder = new SeekableStreamDecoder();
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_md5_checking()... ");
+       if(!decoder->set_md5_checking(true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_serial_number()... ");
+       if(!decoder->set_serial_number(file_utils__serial_number))
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing init()... ");
+       if(decoder->init() != ::OggFLAC__SEEKABLE_STREAM_DECODER_OK)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       OggFLAC::Decoder::SeekableStream::State state = decoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::OggFLAC__SeekableStreamDecoderState)state), state.as_cstring());
+
+       printf("testing get_FLAC_seekable_stream_decoder_state()... ");
+       FLAC::Decoder::SeekableStream::State state_ = decoder->get_FLAC_seekable_stream_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__SeekableStreamDecoderState)state_), state_.as_cstring());
+
+       printf("testing get_FLAC_stream_decoder_state()... ");
+       FLAC::Decoder::Stream::State state__ = decoder->get_FLAC_stream_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)state__), state__.as_cstring());
+
+       decoder->current_metadata_number_ = 0;
+       decoder->ignore_errors_ = false;
+       decoder->error_occurred_ = false;
+
+       printf("opening Ogg FLAC file... ");
+       decoder->file_ = ::fopen(oggflacfilename_, "rb");
+       if(0 == decoder->file_) {
+               printf("ERROR\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_md5_checking()... ");
+       if(!decoder->get_md5_checking()) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing process_until_end_of_metadata()... ");
+       if(!decoder->process_until_end_of_metadata())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_single()... ");
+       if(!decoder->process_single())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing flush()... ");
+       if(!decoder->flush())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       decoder->ignore_errors_ = true;
+       printf("testing process_single()... ");
+       if(!decoder->process_single())
+               return decoder->die("returned false");
+       printf("OK\n");
+       decoder->ignore_errors_ = false;
+
+       printf("testing seek_absolute()... ");
+       if(!decoder->seek_absolute(0))
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_until_end_of_stream()... ");
+       if(!decoder->process_until_end_of_stream())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing get_channels()... ");
+       {
+               unsigned channels = decoder->get_channels();
+               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 get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = decoder->get_bits_per_sample();
+               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 get_sample_rate()... ");
+       {
+               unsigned sample_rate = decoder->get_sample_rate();
+               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 get_blocksize()... ");
+       {
+               unsigned blocksize = decoder->get_blocksize();
+               /* value could be anything since we're at the last block, so accept any answer */
+               printf("returned %u... OK\n", blocksize);
+       }
+
+       printf("testing get_channel_assignment()... ");
+       {
+               ::FLAC__ChannelAssignment ca = decoder->get_channel_assignment();
+               printf("returned %u (%s)... OK\n", (unsigned)ca, ::FLAC__ChannelAssignmentString[ca]);
+       }
+
+       printf("testing reset()... ");
+       if(!decoder->reset())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       decoder->current_metadata_number_ = 0;
+
+       printf("rewinding input... ");
+       if(::fseek(decoder->file_, 0, SEEK_SET) < 0) {
+               printf("FAILED, errno = %d\n", errno);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing process_until_end_of_stream()... ");
+       if(!decoder->process_until_end_of_stream())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       decoder->finish();
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!decoder->set_metadata_ignore(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(APPLICATION)... ");
+       if(!decoder->set_metadata_ignore(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #1)... ");
+       if(!decoder->set_metadata_ignore_application(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #1)... ");
+       if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #2)... ");
+       if(!decoder->set_metadata_ignore_application(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!decoder->set_metadata_respond(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(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond(APPLICATION)... ");
+       if(!decoder->set_metadata_respond(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(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #1)... ");
+       if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #1)... ");
+       if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #2)... ");
+       if(!decoder->set_metadata_respond_application(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(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(APPLICATION)... ");
+       if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #1)... ");
+       if(!decoder->set_metadata_respond_application(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond(APPLICATION)... ");
+       if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #1)... ");
+       if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /* 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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       ::fclose(decoder->file_);
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+class FileDecoder : public OggFLAC::Decoder::File, public DecoderCommon {
+public:
+       FileDecoder(): OggFLAC::Decoder::File(), DecoderCommon() { }
+       ~FileDecoder() { }
+
+       // from OggFLAC::Decoder::File
+       ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+       void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+       void error_callback(::FLAC__StreamDecoderErrorStatus status);
+
+       bool die(const char *msg = 0) const;
+
+       bool test_respond();
+};
+
+::FLAC__StreamDecoderWriteStatus FileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       (void)buffer;
+       return common_write_callback_(frame);
+}
+
+void FileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+       common_metadata_callback_(metadata);
+}
+
+void FileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+       common_error_callback_(status);
+}
+
+bool FileDecoder::die(const char *msg) const
+{
+       State state = get_state();
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)((::OggFLAC__FileDecoderState)state), state.as_cstring());
+       if(state == ::OggFLAC__FILE_DECODER_FLAC_FILE_DECODER_ERROR) {
+               FLAC::Decoder::File::State state_ = get_FLAC_file_decoder_state();
+               printf("      FLAC file decoder state = %u (%s)\n", (unsigned)((::FLAC__FileDecoderState)state_), state_.as_cstring());
+               if(state_ == ::OggFLAC__SEEKABLE_STREAM_DECODER_FLAC_SEEKABLE_STREAM_DECODER_ERROR) {
+                       FLAC::Decoder::SeekableStream::State state__ = get_FLAC_seekable_stream_decoder_state();
+                       printf("      FLAC seekable stream decoder state = %u (%s)\n", (unsigned)((::FLAC__SeekableStreamDecoderState)state__), state__.as_cstring());
+                       if(state__ == ::FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR) {
+                               FLAC::Decoder::Stream::State state___ = get_FLAC_stream_decoder_state();
+                               printf("      FLAC stream decoder state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state___), state___.as_cstring());
+                       }
+               }
+       }
+
+       return false;
+}
+
+bool FileDecoder::test_respond()
+{
+       if(!set_filename(oggflacfilename_)) {
+               printf("FAILED at set_filename(), returned false\n");
+               return false;
+       }
+
+       if(!set_md5_checking(true)) {
+               printf("FAILED at set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       printf("testing init()... ");
+       if(init() != ::OggFLAC__FILE_DECODER_OK)
+               return die();
+       printf("OK\n");
+
+       current_metadata_number_ = 0;
+
+       printf("testing process_until_end_of_file()... ");
+       if(!process_until_end_of_file()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::OggFLAC__FileDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       finish();
+       printf("OK\n");
+
+       return true;
+}
+
+static bool test_file_decoder()
+{
+       FileDecoder *decoder;
+
+       printf("\n+++ libOggFLAC++ unit test: OggFLAC::Decoder::File\n\n");
+
+       //
+       // test new -> delete
+       //
+       printf("allocating decoder instance... ");
+       decoder = new FileDecoder();
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       //
+       // test new -> init -> delete
+       //
+       printf("allocating decoder instance... ");
+       decoder = new FileDecoder();
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing init()... ");
+       if(decoder->init() != ::OggFLAC__FILE_DECODER_OK)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       //
+       // test normal usage
+       //
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("allocating decoder instance... ");
+       decoder = new FileDecoder();
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_filename()... ");
+       if(!decoder->set_filename(oggflacfilename_)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_md5_checking()... ");
+       if(!decoder->set_md5_checking(true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_serial_number()... ");
+       if(!decoder->set_serial_number(file_utils__serial_number))
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing init()... ");
+       if(decoder->init() != ::OggFLAC__FILE_DECODER_OK)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       OggFLAC::Decoder::File::State state = decoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::OggFLAC__FileDecoderState)state), state.as_cstring());
+
+       printf("testing get_FLAC_file_decoder_state()... ");
+       FLAC::Decoder::File::State state_ = decoder->get_FLAC_file_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__FileDecoderState)state_), state_.as_cstring());
+
+       printf("testing get_FLAC_seekable_stream_decoder_state()... ");
+       FLAC::Decoder::SeekableStream::State state__ = decoder->get_FLAC_seekable_stream_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__SeekableStreamDecoderState)state__), state__.as_cstring());
+
+       printf("testing get_FLAC_stream_decoder_state()... ");
+       FLAC::Decoder::Stream::State state___ = decoder->get_FLAC_stream_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)state___), state___.as_cstring());
+
+       decoder->current_metadata_number_ = 0;
+       decoder->ignore_errors_ = false;
+       decoder->error_occurred_ = false;
+
+       printf("testing get_md5_checking()... ");
+       if(!decoder->get_md5_checking()) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing process_until_end_of_metadata()... ");
+       if(!decoder->process_until_end_of_metadata())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_single()... ");
+       if(!decoder->process_single())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing seek_absolute()... ");
+       if(!decoder->seek_absolute(0))
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_until_end_of_file()... ");
+       if(!decoder->process_until_end_of_file())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing get_channels()... ");
+       {
+               unsigned channels = decoder->get_channels();
+               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 get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = decoder->get_bits_per_sample();
+               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 get_sample_rate()... ");
+       {
+               unsigned sample_rate = decoder->get_sample_rate();
+               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 get_blocksize()... ");
+       {
+               unsigned blocksize = decoder->get_blocksize();
+               /* value could be anything since we're at the last block, so accept any answer */
+               printf("returned %u... OK\n", blocksize);
+       }
+
+       printf("testing get_channel_assignment()... ");
+       {
+               ::FLAC__ChannelAssignment ca = decoder->get_channel_assignment();
+               printf("returned %u (%s)... OK\n", (unsigned)ca, ::FLAC__ChannelAssignmentString[ca]);
+       }
+
+       printf("testing finish()... ");
+       decoder->finish();
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!decoder->set_metadata_ignore(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(APPLICATION)... ");
+       if(!decoder->set_metadata_ignore(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #1)... ");
+       if(!decoder->set_metadata_ignore_application(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #1)... ");
+       if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #2)... ");
+       if(!decoder->set_metadata_ignore_application(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!decoder->set_metadata_respond(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(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond(APPLICATION)... ");
+       if(!decoder->set_metadata_respond(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(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #1)... ");
+       if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #1)... ");
+       if(!decoder->set_metadata_respond_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #2)... ");
+       if(!decoder->set_metadata_respond_application(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(!decoder->test_respond())
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(APPLICATION)... ");
+       if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond_application(of app block #1)... ");
+       if(!decoder->set_metadata_respond_application(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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing set_metadata_ignore_all()... ");
+       if(!decoder->set_metadata_ignore_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_respond(APPLICATION)... ");
+       if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_APPLICATION)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore_application(of app block #1)... ");
+       if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!decoder->test_respond())
+               return false;
+
+       /* 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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
 bool test_decoders()
 {
        init_metadata_blocks_();
+
        if(!generate_file_())
                return false;
 
        if(!test_stream_decoder())
                return false;
 
+       if(!test_seekable_stream_decoder())
+               return false;
+
+       if(!test_file_decoder())
+               return false;
+
        (void) grabbag__file_remove_file(oggflacfilename_);
+
        free_metadata_blocks_();
 
        return true;
index 0a30f71..d571681 100644 (file)
@@ -30,6 +30,7 @@ extern "C" {
 static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
 static ::FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_ };
 static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
+static const char *oggflacfilename_ = "metadata.ogg";
 
 static void init_metadata_blocks_()
 {
@@ -48,7 +49,7 @@ public:
 
        // from OggFLAC::Encoder::Stream
        ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame);
-       void metadata_callback(const FLAC__StreamMetadata *metadata);
+       void metadata_callback(const ::FLAC__StreamMetadata *metadata);
 
        bool die(const char *msg = 0) const;
 };
@@ -60,7 +61,7 @@ public:
        return ::FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
 }
 
-void StreamEncoder::metadata_callback(const FLAC__StreamMetadata *metadata)
+void StreamEncoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
 {
        (void)metadata;
 }
@@ -380,6 +381,714 @@ static bool test_stream_encoder()
        return true;
 }
 
+class SeekableStreamEncoder : public OggFLAC::Encoder::SeekableStream {
+public:
+       SeekableStreamEncoder(): OggFLAC::Encoder::SeekableStream() { }
+       ~SeekableStreamEncoder() { }
+
+       // from OggFLAC::Encoder::SeekableStream
+       ::FLAC__SeekableStreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+       ::FLAC__SeekableStreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+       ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame);
+
+       bool die(const char *msg = 0) const;
+};
+
+::FLAC__SeekableStreamEncoderSeekStatus SeekableStreamEncoder::seek_callback(FLAC__uint64 absolute_byte_offset)
+{
+       (void)absolute_byte_offset;
+
+       return ::FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+::FLAC__SeekableStreamEncoderTellStatus SeekableStreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+       (void)absolute_byte_offset;
+
+       return ::FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
+}
+
+::FLAC__StreamEncoderWriteStatus SeekableStreamEncoder::write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame)
+{
+       (void)buffer, (void)bytes, (void)samples, (void)current_frame;
+
+       return ::FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+bool SeekableStreamEncoder::die(const char *msg) const
+{
+       State state = get_state();
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)((::OggFLAC__SeekableStreamEncoderState)state), state.as_cstring());
+       if(state == ::OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR) {
+               FLAC::Encoder::SeekableStream::State state_ = get_FLAC_seekable_stream_encoder_state();
+               printf("      FLAC seekable stream encoder state = %u (%s)\n", (unsigned)((::FLAC__SeekableStreamEncoderState)state_), state_.as_cstring());
+               if(state_ == ::FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR) {
+                       FLAC::Encoder::Stream::State state__ = get_FLAC_stream_encoder_state();
+                       printf("      FLAC stream encoder state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state__), state__.as_cstring());
+                       if(state__ == ::FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+                               FLAC::Decoder::Stream::State dstate = get_verify_decoder_state();
+                               printf("      verify decoder state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+                       }
+               }
+       }
+
+       return false;
+}
+
+static bool test_seekable_stream_encoder()
+{
+       SeekableStreamEncoder *encoder;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1] = { samples };
+       unsigned i;
+
+       printf("\n+++ libOggFLAC++ unit test: OggFLAC::Encoder::SeekableStream\n\n");
+
+       printf("allocating encoder instance... ");
+       encoder = new SeekableStreamEncoder();
+       if(0 == encoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!encoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_serial_number()... ");
+       if(!encoder->set_serial_number(file_utils__serial_number))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_verify()... ");
+       if(!encoder->set_verify(true))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_streamable_subset()... ");
+       if(!encoder->set_streamable_subset(true))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_mid_side_stereo()... ");
+       if(!encoder->set_do_mid_side_stereo(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_loose_mid_side_stereo()... ");
+       if(!encoder->set_loose_mid_side_stereo(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_channels()... ");
+       if(!encoder->set_channels(streaminfo_.data.stream_info.channels))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_bits_per_sample()... ");
+       if(!encoder->set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_sample_rate()... ");
+       if(!encoder->set_sample_rate(streaminfo_.data.stream_info.sample_rate))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_blocksize()... ");
+       if(!encoder->set_blocksize(streaminfo_.data.stream_info.min_blocksize))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_max_lpc_order()... ");
+       if(!encoder->set_max_lpc_order(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_qlp_coeff_precision()... ");
+       if(!encoder->set_qlp_coeff_precision(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_qlp_coeff_prec_search()... ");
+       if(!encoder->set_do_qlp_coeff_prec_search(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_escape_coding()... ");
+       if(!encoder->set_do_escape_coding(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_exhaustive_model_search()... ");
+       if(!encoder->set_do_exhaustive_model_search(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_min_residual_partition_order()... ");
+       if(!encoder->set_min_residual_partition_order(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_max_residual_partition_order()... ");
+       if(!encoder->set_max_residual_partition_order(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_rice_parameter_search_dist()... ");
+       if(!encoder->set_rice_parameter_search_dist(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_total_samples_estimate()... ");
+       if(!encoder->set_total_samples_estimate(streaminfo_.data.stream_info.total_samples))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_metadata()... ");
+       if(!encoder->set_metadata(metadata_sequence_, num_metadata_))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing init()... ");
+       if(encoder->init() != ::OggFLAC__SEEKABLE_STREAM_ENCODER_OK)
+               return encoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       OggFLAC::Encoder::SeekableStream::State state = encoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::OggFLAC__SeekableStreamEncoderState)state), state.as_cstring());
+
+       printf("testing get_FLAC_seekable_stream_encoder_state()... ");
+       FLAC::Encoder::SeekableStream::State state_ = encoder->get_FLAC_seekable_stream_encoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__SeekableStreamEncoderState)state_), state_.as_cstring());
+
+       printf("testing get_FLAC_stream_encoder_state()... ");
+       FLAC::Encoder::Stream::State state__ = encoder->get_FLAC_stream_encoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamEncoderState)state__), state__.as_cstring());
+
+       printf("testing get_verify_decoder_state()... ");
+       FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+
+       {
+               FLAC__uint64 absolute_sample;
+               unsigned frame_number;
+               unsigned channel;
+               unsigned sample;
+               FLAC__int32 expected;
+               FLAC__int32 got;
+
+               printf("testing get_verify_decoder_error_stats()... ");
+               encoder->get_verify_decoder_error_stats(&absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+               printf("OK\n");
+       }
+
+       printf("testing get_verify()... ");
+       if(encoder->get_verify() != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_streamable_subset()... ");
+       if(encoder->get_streamable_subset() != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_mid_side_stereo()... ");
+       if(encoder->get_do_mid_side_stereo() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_loose_mid_side_stereo()... ");
+       if(encoder->get_loose_mid_side_stereo() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_channels()... ");
+       if(encoder->get_channels() != streaminfo_.data.stream_info.channels) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, encoder->get_channels());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_bits_per_sample()... ");
+       if(encoder->get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, encoder->get_bits_per_sample());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_sample_rate()... ");
+       if(encoder->get_sample_rate() != streaminfo_.data.stream_info.sample_rate) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, encoder->get_sample_rate());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_blocksize()... ");
+       if(encoder->get_blocksize() != streaminfo_.data.stream_info.min_blocksize) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, encoder->get_blocksize());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_max_lpc_order()... ");
+       if(encoder->get_max_lpc_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_lpc_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_qlp_coeff_precision()... ");
+       (void)encoder->get_qlp_coeff_precision();
+       /* we asked the encoder to auto select this so we accept anything */
+       printf("OK\n");
+
+       printf("testing get_do_qlp_coeff_prec_search()... ");
+       if(encoder->get_do_qlp_coeff_prec_search() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_escape_coding()... ");
+       if(encoder->get_do_escape_coding() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_exhaustive_model_search()... ");
+       if(encoder->get_do_exhaustive_model_search() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_min_residual_partition_order()... ");
+       if(encoder->get_min_residual_partition_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_min_residual_partition_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_max_residual_partition_order()... ");
+       if(encoder->get_max_residual_partition_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_residual_partition_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_rice_parameter_search_dist()... ");
+       if(encoder->get_rice_parameter_search_dist() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_rice_parameter_search_dist());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_total_samples_estimate()... ");
+       if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) {
+               printf("FAILED, expected %llu, got %llu\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate());
+               return false;
+       }
+       printf("OK\n");
+
+       /* init the dummy sample buffer */
+       for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+               samples[i] = i & 7;
+
+       printf("testing process()... ");
+       if(!encoder->process(samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_interleaved()... ");
+       if(!encoder->process_interleaved(samples, sizeof(samples) / sizeof(FLAC__int32)))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       encoder->finish();
+       printf("OK\n");
+
+       printf("freeing encoder instance... ");
+       delete encoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+class FileEncoder : public OggFLAC::Encoder::File {
+public:
+       FileEncoder(): OggFLAC::Encoder::File() { }
+       ~FileEncoder() { }
+
+       // from OggFLAC::Encoder::File
+       void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
+
+       bool die(const char *msg = 0) const;
+};
+
+void FileEncoder::progress_callback(FLAC__uint64, FLAC__uint64, unsigned, unsigned)
+{
+}
+
+bool FileEncoder::die(const char *msg) const
+{
+       State state = get_state();
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)((::OggFLAC__FileEncoderState)state), state.as_cstring());
+       if(state == ::OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR) {
+               OggFLAC::Encoder::SeekableStream::State state_ = get_seekable_stream_encoder_state();
+               printf("      seekable stream encoder state = %u (%s)\n", (unsigned)((::OggFLAC__SeekableStreamEncoderState)state_), state_.as_cstring());
+               if(state_ == ::OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR) {
+                       FLAC::Encoder::SeekableStream::State state__ = get_FLAC_seekable_stream_encoder_state();
+                       printf("      FLAC seekable stream encoder state = %u (%s)\n", (unsigned)((::FLAC__SeekableStreamEncoderState)state__), state__.as_cstring());
+                       if(state__ == ::FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR) {
+                               FLAC::Encoder::Stream::State state___ = get_FLAC_stream_encoder_state();
+                               printf("      FLAC stream encoder state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state___), state___.as_cstring());
+                               if(state___ == ::FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+                                       FLAC::Decoder::Stream::State dstate = get_verify_decoder_state();
+                                       printf("      verify decoder state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
+static bool test_file_encoder()
+{
+       FileEncoder *encoder;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1] = { samples };
+       unsigned i;
+
+       printf("\n+++ libOggFLAC++ unit test: OggFLAC::Encoder::File\n\n");
+
+       printf("allocating encoder instance... ");
+       encoder = new FileEncoder();
+       if(0 == encoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!encoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_serial_number()... ");
+       if(!encoder->set_serial_number(file_utils__serial_number))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_verify()... ");
+       if(!encoder->set_verify(true))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_streamable_subset()... ");
+       if(!encoder->set_streamable_subset(true))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_mid_side_stereo()... ");
+       if(!encoder->set_do_mid_side_stereo(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_loose_mid_side_stereo()... ");
+       if(!encoder->set_loose_mid_side_stereo(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_channels()... ");
+       if(!encoder->set_channels(streaminfo_.data.stream_info.channels))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_bits_per_sample()... ");
+       if(!encoder->set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_sample_rate()... ");
+       if(!encoder->set_sample_rate(streaminfo_.data.stream_info.sample_rate))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_blocksize()... ");
+       if(!encoder->set_blocksize(streaminfo_.data.stream_info.min_blocksize))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_max_lpc_order()... ");
+       if(!encoder->set_max_lpc_order(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_qlp_coeff_precision()... ");
+       if(!encoder->set_qlp_coeff_precision(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_qlp_coeff_prec_search()... ");
+       if(!encoder->set_do_qlp_coeff_prec_search(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_escape_coding()... ");
+       if(!encoder->set_do_escape_coding(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_do_exhaustive_model_search()... ");
+       if(!encoder->set_do_exhaustive_model_search(false))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_min_residual_partition_order()... ");
+       if(!encoder->set_min_residual_partition_order(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_max_residual_partition_order()... ");
+       if(!encoder->set_max_residual_partition_order(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_rice_parameter_search_dist()... ");
+       if(!encoder->set_rice_parameter_search_dist(0))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_total_samples_estimate()... ");
+       if(!encoder->set_total_samples_estimate(streaminfo_.data.stream_info.total_samples))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_metadata()... ");
+       if(!encoder->set_metadata(metadata_sequence_, num_metadata_))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing set_filename()... ");
+       if(!encoder->set_filename(oggflacfilename_))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing init()... ");
+       if(encoder->init() != ::OggFLAC__FILE_ENCODER_OK)
+               return encoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       OggFLAC::Encoder::File::State state = encoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::OggFLAC__FileEncoderState)state), state.as_cstring());
+
+       printf("testing get_seekable_stream_encoder_state()... ");
+       OggFLAC::Encoder::SeekableStream::State state_ = encoder->get_seekable_stream_encoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::OggFLAC__SeekableStreamEncoderState)state_), state_.as_cstring());
+
+       printf("testing get_FLAC_seekable_stream_encoder_state()... ");
+       FLAC::Encoder::SeekableStream::State state__ = encoder->get_FLAC_seekable_stream_encoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__SeekableStreamEncoderState)state__), state__.as_cstring());
+
+       printf("testing get_FLAC_stream_encoder_state()... ");
+       FLAC::Encoder::Stream::State state___ = encoder->get_FLAC_stream_encoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamEncoderState)state___), state___.as_cstring());
+
+       printf("testing get_verify_decoder_state()... ");
+       FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+
+       {
+               FLAC__uint64 absolute_sample;
+               unsigned frame_number;
+               unsigned channel;
+               unsigned sample;
+               FLAC__int32 expected;
+               FLAC__int32 got;
+
+               printf("testing get_verify_decoder_error_stats()... ");
+               encoder->get_verify_decoder_error_stats(&absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+               printf("OK\n");
+       }
+
+       printf("testing get_verify()... ");
+       if(encoder->get_verify() != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_streamable_subset()... ");
+       if(encoder->get_streamable_subset() != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_mid_side_stereo()... ");
+       if(encoder->get_do_mid_side_stereo() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_loose_mid_side_stereo()... ");
+       if(encoder->get_loose_mid_side_stereo() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_channels()... ");
+       if(encoder->get_channels() != streaminfo_.data.stream_info.channels) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, encoder->get_channels());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_bits_per_sample()... ");
+       if(encoder->get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, encoder->get_bits_per_sample());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_sample_rate()... ");
+       if(encoder->get_sample_rate() != streaminfo_.data.stream_info.sample_rate) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, encoder->get_sample_rate());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_blocksize()... ");
+       if(encoder->get_blocksize() != streaminfo_.data.stream_info.min_blocksize) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, encoder->get_blocksize());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_max_lpc_order()... ");
+       if(encoder->get_max_lpc_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_lpc_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_qlp_coeff_precision()... ");
+       (void)encoder->get_qlp_coeff_precision();
+       /* we asked the encoder to auto select this so we accept anything */
+       printf("OK\n");
+
+       printf("testing get_do_qlp_coeff_prec_search()... ");
+       if(encoder->get_do_qlp_coeff_prec_search() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_escape_coding()... ");
+       if(encoder->get_do_escape_coding() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_exhaustive_model_search()... ");
+       if(encoder->get_do_exhaustive_model_search() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_min_residual_partition_order()... ");
+       if(encoder->get_min_residual_partition_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_min_residual_partition_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_max_residual_partition_order()... ");
+       if(encoder->get_max_residual_partition_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_residual_partition_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_rice_parameter_search_dist()... ");
+       if(encoder->get_rice_parameter_search_dist() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_rice_parameter_search_dist());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_total_samples_estimate()... ");
+       if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) {
+               printf("FAILED, expected %llu, got %llu\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate());
+               return false;
+       }
+       printf("OK\n");
+
+       /* init the dummy sample buffer */
+       for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+               samples[i] = i & 7;
+
+       printf("testing process()... ");
+       if(!encoder->process(samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_interleaved()... ");
+       if(!encoder->process_interleaved(samples, sizeof(samples) / sizeof(FLAC__int32)))
+               return encoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       encoder->finish();
+       printf("OK\n");
+
+       printf("freeing encoder instance... ");
+       delete encoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
 bool test_encoders()
 {
        init_metadata_blocks_();
@@ -387,6 +1096,12 @@ bool test_encoders()
        if(!test_stream_encoder())
                return false;
 
+       if(!test_seekable_stream_encoder())
+               return false;
+
+       if(!test_file_encoder())
+               return false;
+
        free_metadata_blocks_();
 
        return true;
index 1204f7f..7238311 100644 (file)
@@ -20,6 +20,8 @@
 #include "file_utils.h"
 #include "metadata_utils.h"
 #include "FLAC/assert.h"
+#include "OggFLAC/file_decoder.h"
+#include "OggFLAC/seekable_stream_decoder.h"
 #include "OggFLAC/stream_decoder.h"
 #include "share/grabbag.h"
 #include <errno.h>
@@ -34,6 +36,9 @@ typedef struct {
        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_, cuesheet_, unknown_;
 static FLAC__StreamMetadata *expected_metadata_sequence_[8];
 static unsigned num_expected_;
@@ -64,6 +69,54 @@ static FLAC__bool die_s_(const char *msg, const OggFLAC__StreamDecoder *decoder)
        return false;
 }
 
+static FLAC__bool die_ss_(const char *msg, const OggFLAC__SeekableStreamDecoder *decoder)
+{
+       OggFLAC__SeekableStreamDecoderState state = OggFLAC__seekable_stream_decoder_get_state(decoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, OggFLAC__SeekableStreamDecoderStateString[state]);
+       if(state == OggFLAC__SEEKABLE_STREAM_DECODER_FLAC_SEEKABLE_STREAM_DECODER_ERROR) {
+               FLAC__SeekableStreamDecoderState state_ = OggFLAC__seekable_stream_decoder_get_FLAC_seekable_stream_decoder_state(decoder);
+               printf("      FLAC seekable stream decoder state = %u (%s)\n", (unsigned)state_, FLAC__SeekableStreamDecoderStateString[state_]);
+               if(state_ == FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR) {
+                       FLAC__StreamDecoderState state__ = OggFLAC__seekable_stream_decoder_get_FLAC_stream_decoder_state(decoder);
+                       printf("      FLAC stream decoder state = %u (%s)\n", (unsigned)state__, FLAC__StreamDecoderStateString[state__]);
+               }
+       }
+
+       return false;
+}
+
+static FLAC__bool die_f_(const char *msg, const OggFLAC__FileDecoder *decoder)
+{
+       OggFLAC__FileDecoderState state = OggFLAC__file_decoder_get_state(decoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, OggFLAC__SeekableStreamDecoderStateString[state]);
+       if(state == OggFLAC__FILE_DECODER_FLAC_FILE_DECODER_ERROR) {
+               FLAC__FileDecoderState state_ = OggFLAC__file_decoder_get_FLAC_file_decoder_state(decoder);
+               printf("      FLAC file decoder state = %u (%s)\n", (unsigned)state_, FLAC__FileDecoderStateString[state_]);
+               if(state_ == FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR) {
+                       FLAC__SeekableStreamDecoderState state__ = OggFLAC__file_decoder_get_FLAC_seekable_stream_decoder_state(decoder);
+                       printf("      FLAC seekable stream decoder state = %u (%s)\n", (unsigned)state__, FLAC__SeekableStreamDecoderStateString[state__]);
+                       if(state__ == FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR) {
+                               FLAC__StreamDecoderState state___ = OggFLAC__file_decoder_get_FLAC_stream_decoder_state(decoder);
+                               printf("      FLAC stream decoder state = %u (%s)\n", (unsigned)state___, FLAC__StreamDecoderStateString[state___]);
+                       }
+               }
+       }
+
+       return false;
+}
+
 static void init_metadata_blocks_()
 {
        mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
@@ -243,6 +296,7 @@ static FLAC__bool test_stream_decoder()
 {
        OggFLAC__StreamDecoder *decoder;
        OggFLAC__StreamDecoderState state;
+       FLAC__StreamDecoderState fstate;
        stream_decoder_client_data_struct decoder_client_data;
 
        printf("\n+++ libOggFLAC unit test: OggFLAC__StreamDecoder\n\n");
@@ -326,6 +380,10 @@ static FLAC__bool test_stream_decoder()
        state = OggFLAC__stream_decoder_get_state(decoder);
        printf("returned state = %u (%s)... OK\n", state, OggFLAC__StreamDecoderStateString[state]);
 
+       printf("testing OggFLAC__stream_decoder_get_FLAC_stream_decoder_state()... ");
+       fstate = OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(decoder);
+       printf("returned state = %u (%s)... OK\n", fstate, FLAC__StreamDecoderStateString[fstate]);
+
        decoder_client_data.current_metadata_number = 0;
        decoder_client_data.ignore_errors = false;
        decoder_client_data.error_occurred = false;
@@ -742,13 +800,1286 @@ static FLAC__bool test_stream_decoder()
        return true;
 }
 
-FLAC__bool test_decoders()
+static FLAC__SeekableStreamDecoderReadStatus seekable_stream_decoder_read_callback_(const OggFLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
 {
-       init_metadata_blocks_();
-       if(!generate_file_())
+       (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 OggFLAC__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, (long)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 OggFLAC__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 OggFLAC__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)oggflacfilesize_;
+       return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool seekable_stream_decoder_eof_callback_(const OggFLAC__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 OggFLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       (void)decoder;
+       return stream_decoder_write_callback_(0, frame, buffer, client_data);
+}
+
+static void seekable_stream_decoder_metadata_callback_(const OggFLAC__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 OggFLAC__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_(OggFLAC__SeekableStreamDecoder *decoder, seekable_stream_decoder_client_data_struct *dcd)
+{
+       if(!OggFLAC__seekable_stream_decoder_set_read_callback(decoder, seekable_stream_decoder_read_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_read_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_seek_callback(decoder, seekable_stream_decoder_seek_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_seek_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_tell_callback(decoder, seekable_stream_decoder_tell_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_tell_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_length_callback(decoder, seekable_stream_decoder_length_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_length_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_eof_callback(decoder, seekable_stream_decoder_eof_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_eof_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_write_callback(decoder, seekable_stream_decoder_write_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_write_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_callback(decoder, seekable_stream_decoder_metadata_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_metadata_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_error_callback(decoder, seekable_stream_decoder_error_callback_))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_error_callback(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_client_data(decoder, dcd))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_client_data(), returned false", decoder);
+
+       if(!OggFLAC__seekable_stream_decoder_set_md5_checking(decoder, true))
+               return die_ss_("at OggFLAC__seekable_stream_decoder_set_md5_checking(), returned false", decoder);
+
+       printf("testing OggFLAC__seekable_stream_decoder_init()... ");
+       if(OggFLAC__seekable_stream_decoder_init(decoder) != OggFLAC__SEEKABLE_STREAM_DECODER_OK)
+               return die_ss_(0, decoder);
+       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;
+       }
 
-       if(!test_stream_decoder())
+       printf("testing OggFLAC__seekable_stream_decoder_process_until_end_of_stream()... ");
+       if(!OggFLAC__seekable_stream_decoder_process_until_end_of_stream(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_finish()... ");
+       (void) OggFLAC__seekable_stream_decoder_finish(decoder);
+       printf("OK\n");
+
+       return true;
+}
+
+static FLAC__bool test_seekable_stream_decoder()
+{
+       OggFLAC__SeekableStreamDecoder *decoder;
+       OggFLAC__SeekableStreamDecoderState state;
+       FLAC__SeekableStreamDecoderState fsstate;
+       FLAC__StreamDecoderState fstate;
+       seekable_stream_decoder_client_data_struct decoder_client_data;
+
+       printf("\n+++ libOggFLAC unit test: OggFLAC__SeekableStreamDecoder\n\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_new()... ");
+       decoder = OggFLAC__seekable_stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_delete()... ");
+       OggFLAC__seekable_stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_new()... ");
+       decoder = OggFLAC__seekable_stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_init()... ");
+       if(OggFLAC__seekable_stream_decoder_init(decoder) == OggFLAC__SEEKABLE_STREAM_DECODER_OK)
+               return die_ss_(0, decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_delete()... ");
+       OggFLAC__seekable_stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("testing OggFLAC__seekable_stream_decoder_new()... ");
+       decoder = OggFLAC__seekable_stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_serial_number()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_serial_number(decoder, file_utils__serial_number))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_read_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_read_callback(decoder, seekable_stream_decoder_read_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_seek_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_seek_callback(decoder, seekable_stream_decoder_seek_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_tell_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_tell_callback(decoder, seekable_stream_decoder_tell_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_length_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_length_callback(decoder, seekable_stream_decoder_length_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_eof_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_eof_callback(decoder, seekable_stream_decoder_eof_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_write_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_write_callback(decoder, seekable_stream_decoder_write_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_callback(decoder, seekable_stream_decoder_metadata_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_error_callback()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_error_callback(decoder, seekable_stream_decoder_error_callback_))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_client_data()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_client_data(decoder, &decoder_client_data))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_md5_checking()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_md5_checking(decoder, true))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_init()... ");
+       if(OggFLAC__seekable_stream_decoder_init(decoder) != OggFLAC__SEEKABLE_STREAM_DECODER_OK)
+               return die_ss_(0, decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_get_state()... ");
+       state = OggFLAC__seekable_stream_decoder_get_state(decoder);
+       printf("returned state = %u (%s)... OK\n", state, OggFLAC__SeekableStreamDecoderStateString[state]);
+
+       printf("testing OggFLAC__seekable_stream_decoder_get_FLAC_seekable_stream_decoder_state()... ");
+       fsstate = OggFLAC__seekable_stream_decoder_get_FLAC_seekable_stream_decoder_state(decoder);
+       printf("returned state = %u (%s)... OK\n", fsstate, FLAC__SeekableStreamDecoderStateString[fsstate]);
+
+       printf("testing OggFLAC__seekable_stream_decoder_get_FLAC_stream_decoder_state()... ");
+       fstate = OggFLAC__seekable_stream_decoder_get_FLAC_stream_decoder_state(decoder);
+       printf("returned state = %u (%s)... OK\n", fstate, FLAC__StreamDecoderStateString[fstate]);
+
+       decoder_client_data.current_metadata_number = 0;
+       decoder_client_data.ignore_errors = false;
+       decoder_client_data.error_occurred = false;
+
+       printf("opening Ogg FLAC file... ");
+       decoder_client_data.file = fopen(oggflacfilename_, "rb");
+       if(0 == decoder_client_data.file) {
+               printf("ERROR\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_get_md5_checking()... ");
+       if(!OggFLAC__seekable_stream_decoder_get_md5_checking(decoder)) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_process_until_end_of_metadata()... ");
+       if(!OggFLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_process_single()... ");
+       if(!OggFLAC__seekable_stream_decoder_process_single(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_flush()... ");
+       if(!OggFLAC__seekable_stream_decoder_flush(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       decoder_client_data.ignore_errors = true;
+       printf("testing OggFLAC__seekable_stream_decoder_process_single()... ");
+       if(!OggFLAC__seekable_stream_decoder_process_single(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+       decoder_client_data.ignore_errors = false;
+
+       printf("testing OggFLAC__seekable_stream_decoder_seek_absolute()... ");
+       if(!OggFLAC__seekable_stream_decoder_seek_absolute(decoder, 0))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_process_until_end_of_stream()... ");
+       if(!OggFLAC__seekable_stream_decoder_process_until_end_of_stream(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_get_channels()... ");
+       {
+               unsigned channels = OggFLAC__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 OggFLAC__seekable_stream_decoder_get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = OggFLAC__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 OggFLAC__seekable_stream_decoder_get_sample_rate()... ");
+       {
+               unsigned sample_rate = OggFLAC__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 OggFLAC__seekable_stream_decoder_get_blocksize()... ");
+       {
+               unsigned blocksize = OggFLAC__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 OggFLAC__seekable_stream_decoder_get_channel_assignment()... ");
+       {
+               FLAC__ChannelAssignment ca = OggFLAC__seekable_stream_decoder_get_channel_assignment(decoder);
+               printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+       }
+
+       printf("testing OggFLAC__seekable_stream_decoder_reset()... ");
+       if(!OggFLAC__seekable_stream_decoder_reset(decoder))
+               return die_ss_("returned false", decoder);
+       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 OggFLAC__seekable_stream_decoder_process_until_end_of_stream()... ");
+       if(!OggFLAC__seekable_stream_decoder_process_until_end_of_stream(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_finish()... ");
+       (void) OggFLAC__seekable_stream_decoder_finish(decoder);
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder))
+               return die_ss_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+               return die_ss_("returned false", decoder);
+       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_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_ss_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_ss_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #2)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id))
+               return die_ss_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_ss_("returned false", decoder);
+       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 false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #2)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id))
+               return die_ss_("returned false", decoder);
+       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 false;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_ss_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!OggFLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!seekable_stream_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /* 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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       printf("testing OggFLAC__seekable_stream_decoder_delete()... ");
+       OggFLAC__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 OggFLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       (void)decoder;
+       return stream_decoder_write_callback_(0, frame, buffer, client_data);
+}
+
+static void file_decoder_metadata_callback_(const OggFLAC__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 OggFLAC__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_(OggFLAC__FileDecoder *decoder, file_decoder_client_data_struct *dcd)
+{
+       if(!OggFLAC__file_decoder_set_write_callback(decoder, file_decoder_write_callback_))
+               return die_f_("at OggFLAC__file_decoder_set_write_callback(), returned false", decoder);
+
+       if(!OggFLAC__file_decoder_set_metadata_callback(decoder, file_decoder_metadata_callback_))
+               return die_f_("at OggFLAC__file_decoder_set_metadata_callback(), returned false", decoder);
+
+       if(!OggFLAC__file_decoder_set_error_callback(decoder, file_decoder_error_callback_))
+               return die_f_("at OggFLAC__file_decoder_set_error_callback(), returned false", decoder);
+
+       if(!OggFLAC__file_decoder_set_client_data(decoder, dcd))
+               return die_f_("at OggFLAC__file_decoder_set_client_data(), returned false", decoder);
+
+       if(!OggFLAC__file_decoder_set_filename(decoder, oggflacfilename_))
+               return die_f_("at OggFLAC__file_decoder_set_filename(), returned false", decoder);
+
+       if(!OggFLAC__file_decoder_set_md5_checking(decoder, true))
+               return die_f_("at OggFLAC__file_decoder_set_md5_checking(), returned false", decoder);
+
+       printf("testing OggFLAC__file_decoder_init()... ");
+       if(OggFLAC__file_decoder_init(decoder) != OggFLAC__FILE_DECODER_OK)
+               return die_f_(0, decoder);
+       printf("OK\n");
+
+       dcd->current_metadata_number = 0;
+
+       printf("testing OggFLAC__file_decoder_process_until_end_of_file()... ");
+       if(!OggFLAC__file_decoder_process_until_end_of_file(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_finish()... ");
+       (void) OggFLAC__file_decoder_finish(decoder);
+       printf("OK\n");
+
+       return true;
+}
+
+static FLAC__bool test_file_decoder()
+{
+       OggFLAC__FileDecoder *decoder;
+       OggFLAC__FileDecoderState state;
+       FLAC__FileDecoderState ffstate;
+       FLAC__SeekableStreamDecoderState fsstate;
+       FLAC__StreamDecoderState fstate;
+       seekable_stream_decoder_client_data_struct decoder_client_data;
+
+       printf("\n+++ libOggFLAC unit test: OggFLAC__FileDecoder\n\n");
+
+       printf("testing OggFLAC__file_decoder_new()... ");
+       decoder = OggFLAC__file_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_delete()... ");
+       OggFLAC__file_decoder_delete(decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_new()... ");
+       decoder = OggFLAC__file_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_init()... ");
+       if(OggFLAC__file_decoder_init(decoder) == OggFLAC__FILE_DECODER_OK)
+               return die_f_(0, decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_delete()... ");
+       OggFLAC__file_decoder_delete(decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("testing OggFLAC__file_decoder_new()... ");
+       decoder = OggFLAC__file_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_serial_number()... ");
+       if(!OggFLAC__file_decoder_set_serial_number(decoder, file_utils__serial_number))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_write_callback()... ");
+       if(!OggFLAC__file_decoder_set_write_callback(decoder, file_decoder_write_callback_))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_callback()... ");
+       if(!OggFLAC__file_decoder_set_metadata_callback(decoder, file_decoder_metadata_callback_))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_error_callback()... ");
+       if(!OggFLAC__file_decoder_set_error_callback(decoder, file_decoder_error_callback_))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_client_data()... ");
+       if(!OggFLAC__file_decoder_set_client_data(decoder, &decoder_client_data))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_filename()... ");
+       if(!OggFLAC__file_decoder_set_filename(decoder, oggflacfilename_))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_md5_checking()... ");
+       if(!OggFLAC__file_decoder_set_md5_checking(decoder, true))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_init()... ");
+       if(OggFLAC__file_decoder_init(decoder) != OggFLAC__FILE_DECODER_OK)
+               return die_f_(0, decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_get_state()... ");
+       state = OggFLAC__file_decoder_get_state(decoder);
+       printf("returned state = %u (%s)... OK\n", state, OggFLAC__FileDecoderStateString[state]);
+
+       printf("testing OggFLAC__file_decoder_get_FLAC_file_decoder_state()... ");
+       ffstate = OggFLAC__file_decoder_get_FLAC_file_decoder_state(decoder);
+       printf("returned state = %u (%s)... OK\n", ffstate, FLAC__FileDecoderStateString[ffstate]);
+
+       printf("testing OggFLAC__file_decoder_get_FLAC_seekable_stream_decoder_state()... ");
+       fsstate = OggFLAC__file_decoder_get_FLAC_seekable_stream_decoder_state(decoder);
+       printf("returned state = %u (%s)... OK\n", fsstate, FLAC__SeekableStreamDecoderStateString[fsstate]);
+
+       printf("testing OggFLAC__file_decoder_get_FLAC_stream_decoder_state()... ");
+       fstate = OggFLAC__file_decoder_get_FLAC_stream_decoder_state(decoder);
+       printf("returned state = %u (%s)... OK\n", fstate, FLAC__StreamDecoderStateString[fstate]);
+
+       decoder_client_data.current_metadata_number = 0;
+       decoder_client_data.ignore_errors = false;
+       decoder_client_data.error_occurred = false;
+
+       printf("testing OggFLAC__file_decoder_get_md5_checking()... ");
+       if(!OggFLAC__file_decoder_get_md5_checking(decoder)) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_process_until_end_of_metadata()... ");
+       if(!OggFLAC__file_decoder_process_until_end_of_metadata(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_process_single()... ");
+       if(!OggFLAC__file_decoder_process_single(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_seek_absolute()... ");
+       if(!OggFLAC__file_decoder_seek_absolute(decoder, 0))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_process_until_end_of_file()... ");
+       if(!OggFLAC__file_decoder_process_until_end_of_file(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_get_channels()... ");
+       {
+               unsigned channels = OggFLAC__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 OggFLAC__file_decoder_get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = OggFLAC__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 OggFLAC__file_decoder_get_sample_rate()... ");
+       {
+               unsigned sample_rate = OggFLAC__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 OggFLAC__file_decoder_get_blocksize()... ");
+       {
+               unsigned blocksize = OggFLAC__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 OggFLAC__file_decoder_get_channel_assignment()... ");
+       {
+               FLAC__ChannelAssignment ca = OggFLAC__file_decoder_get_channel_assignment(decoder);
+               printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+       }
+
+       printf("testing OggFLAC__file_decoder_finish()... ");
+       (void) OggFLAC__file_decoder_finish(decoder);
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_all(decoder))
+               return die_f_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+               return die_f_("returned false", decoder);
+       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_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_f_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_f_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_application(of app block #2)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id))
+               return die_f_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_f_("returned false", decoder);
+       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 false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_application(of app block #2)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_application(decoder, application2_.data.application.id))
+               return die_f_("returned false", decoder);
+       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 false;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_f_("returned false", decoder);
+       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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_all()... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_all(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!OggFLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!OggFLAC__file_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!file_decoder_test_respond_(decoder, &decoder_client_data))
+               return false;
+
+       /* 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_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       printf("testing OggFLAC__file_decoder_delete()... ");
+       OggFLAC__file_decoder_delete(decoder);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+FLAC__bool test_decoders()
+{
+       init_metadata_blocks_();
+       if(!generate_file_())
+               return false;
+
+       if(!test_stream_decoder())
+               return false;
+
+       if(!test_seekable_stream_decoder())
+               return false;
+
+       if(!test_file_decoder())
                return false;
 
        (void) grabbag__file_remove_file(oggflacfilename_);
index 40c06fa..f4e783e 100644 (file)
@@ -20,6 +20,8 @@
 #include "file_utils.h"
 #include "metadata_utils.h"
 #include "FLAC/assert.h"
+#include "OggFLAC/file_encoder.h"
+#include "OggFLAC/seekable_stream_encoder.h"
 #include "OggFLAC/stream_encoder.h"
 #include "share/grabbag.h"
 #include <stdio.h>
@@ -53,6 +55,62 @@ static FLAC__bool die_s_(const char *msg, const OggFLAC__StreamEncoder *encoder)
        return false;
 }
 
+static FLAC__bool die_ss_(const char *msg, const OggFLAC__SeekableStreamEncoder *encoder)
+{
+       OggFLAC__SeekableStreamEncoderState state = OggFLAC__seekable_stream_encoder_get_state(encoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, OggFLAC__SeekableStreamEncoderStateString[state]);
+       if(state == OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR) {
+               FLAC__SeekableStreamEncoderState state_ = OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state(encoder);
+               printf("      FLAC seekable stream encoder state = %u (%s)\n", (unsigned)state_, FLAC__SeekableStreamEncoderStateString[state_]);
+               if(state_ == FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR) {
+                       FLAC__StreamEncoderState state__ = OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(encoder);
+                       printf("      FLAC stream encoder state = %u (%s)\n", (unsigned)state__, FLAC__StreamEncoderStateString[state__]);
+                       if(state__ == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+                               FLAC__StreamDecoderState dstate = OggFLAC__seekable_stream_encoder_get_verify_decoder_state(encoder);
+                               printf("      verify decoder state = %u (%s)\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+                       }
+               }
+       }
+
+       return false;
+}
+
+static FLAC__bool die_f_(const char *msg, const OggFLAC__FileEncoder *encoder)
+{
+       OggFLAC__FileEncoderState state = OggFLAC__file_encoder_get_state(encoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, OggFLAC__SeekableStreamEncoderStateString[state]);
+       if(state == OggFLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR) {
+               OggFLAC__SeekableStreamEncoderState state_ = OggFLAC__file_encoder_get_seekable_stream_encoder_state(encoder);
+               printf("      seekable stream encoder state = %u (%s)\n", (unsigned)state_, OggFLAC__SeekableStreamEncoderStateString[state_]);
+               if(state_ == OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_SEEKABLE_STREAM_ENCODER_ERROR) {
+                       FLAC__SeekableStreamEncoderState state__ = OggFLAC__file_encoder_get_FLAC_seekable_stream_encoder_state(encoder);
+                       printf("      FLAC seekable stream encoder state = %u (%s)\n", (unsigned)state__, FLAC__SeekableStreamEncoderStateString[state__]);
+                       if(state__ == FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR) {
+                               FLAC__StreamEncoderState state___ = OggFLAC__file_encoder_get_FLAC_stream_encoder_state(encoder);
+                               printf("      FLAC stream encoder state = %u (%s)\n", (unsigned)state___, FLAC__StreamEncoderStateString[state___]);
+                               if(state___ == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+                                       FLAC__StreamDecoderState dstate = OggFLAC__file_encoder_get_verify_decoder_state(encoder);
+                                       printf("      verify decoder state = %u (%s)\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
 static void init_metadata_blocks_()
 {
        mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
@@ -79,7 +137,7 @@ static FLAC__bool test_stream_encoder()
 {
        OggFLAC__StreamEncoder *encoder;
        OggFLAC__StreamEncoderState state;
-       FLAC__StreamEncoderState state_;
+       FLAC__StreamEncoderState fstate;
        FLAC__StreamDecoderState dstate;
        FLAC__int32 samples[1024];
        FLAC__int32 *samples_array[1];
@@ -217,8 +275,8 @@ static FLAC__bool test_stream_encoder()
        printf("returned state = %u (%s)... OK\n", (unsigned)state, OggFLAC__StreamEncoderStateString[state]);
 
        printf("testing OggFLAC__stream_encoder_get_FLAC_stream_encoder_state()... ");
-       state_ = OggFLAC__stream_encoder_get_FLAC_stream_encoder_state(encoder);
-       printf("returned state = %u (%s)... OK\n", (unsigned)state_, FLAC__StreamEncoderStateString[state_]);
+       fstate = OggFLAC__stream_encoder_get_FLAC_stream_encoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)fstate, FLAC__StreamEncoderStateString[fstate]);
 
        printf("testing OggFLAC__stream_encoder_get_verify_decoder_state()... ");
        dstate = OggFLAC__stream_encoder_get_verify_decoder_state(encoder);
@@ -381,6 +439,661 @@ static FLAC__bool test_stream_encoder()
        return true;
 }
 
+FLAC__SeekableStreamEncoderSeekStatus seekable_stream_encoder_seek_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       (void)encoder, (void)absolute_byte_offset, (void)client_data;
+       return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+FLAC__SeekableStreamEncoderTellStatus seekable_stream_encoder_tell_callback_(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       (void)encoder, (void)absolute_byte_offset, (void)client_data;
+       return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
+}
+
+FLAC__StreamEncoderWriteStatus seekable_stream_encoder_write_callback_(const OggFLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+       (void)encoder, (void)buffer, (void)bytes, (void)samples, (void)current_frame, (void)client_data;
+       return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static FLAC__bool test_seekable_stream_encoder()
+{
+       OggFLAC__SeekableStreamEncoder *encoder;
+       OggFLAC__SeekableStreamEncoderState state;
+       FLAC__SeekableStreamEncoderState fsstate;
+       FLAC__StreamEncoderState fstate;
+       FLAC__StreamDecoderState dstate;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1];
+       unsigned i;
+
+       samples_array[0] = samples;
+
+       printf("\n+++ libOggFLAC unit test: OggFLAC__SeekableStreamEncoder\n\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_new()... ");
+       encoder = OggFLAC__seekable_stream_encoder_new();
+       if(0 == encoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_serial_number()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_serial_number(encoder, file_utils__serial_number))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_verify()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_verify(encoder, true))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_streamable_subset()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_streamable_subset(encoder, true))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder, false))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder, false))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_channels()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_channels(encoder, streaminfo_.data.stream_info.channels))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_bits_per_sample()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_bits_per_sample(encoder, streaminfo_.data.stream_info.bits_per_sample))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_sample_rate()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_sample_rate(encoder, streaminfo_.data.stream_info.sample_rate))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_blocksize()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_blocksize(encoder, streaminfo_.data.stream_info.min_blocksize))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_max_lpc_order()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_max_lpc_order(encoder, 0))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder, 0))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder, false))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_do_escape_coding()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_do_escape_coding(encoder, false))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder, false))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_min_residual_partition_order()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder, 0))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_max_residual_partition_order()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder, 0))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder, 0))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_total_samples_estimate()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_total_samples_estimate(encoder, streaminfo_.data.stream_info.total_samples))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_metadata()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_metadata(encoder, metadata_sequence_, num_metadata_))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_seek_callback()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_seek_callback(encoder, seekable_stream_encoder_seek_callback_))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_tell_callback()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_tell_callback(encoder, seekable_stream_encoder_tell_callback_))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_write_callback()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_write_callback(encoder, seekable_stream_encoder_write_callback_))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_set_client_data()... ");
+       if(!OggFLAC__seekable_stream_encoder_set_client_data(encoder, 0))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_init()... ");
+       if(OggFLAC__seekable_stream_encoder_init(encoder) != OggFLAC__SEEKABLE_STREAM_ENCODER_OK)
+               return die_ss_(0, encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_state()... ");
+       state = OggFLAC__seekable_stream_encoder_get_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)state, OggFLAC__SeekableStreamEncoderStateString[state]);
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state()... ");
+       fsstate = OggFLAC__seekable_stream_encoder_get_FLAC_seekable_stream_encoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)fsstate, FLAC__SeekableStreamEncoderStateString[fsstate]);
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state()... ");
+       fstate = OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)fstate, FLAC__StreamEncoderStateString[fstate]);
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_verify_decoder_state()... ");
+       dstate = OggFLAC__seekable_stream_encoder_get_verify_decoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+
+       {
+               FLAC__uint64 absolute_sample;
+               unsigned frame_number;
+               unsigned channel;
+               unsigned sample;
+               FLAC__int32 expected;
+               FLAC__int32 got;
+
+               printf("testing OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats()... ");
+               OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+               printf("OK\n");
+       }
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_verify()... ");
+       if(OggFLAC__seekable_stream_encoder_get_verify(encoder) != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_streamable_subset()... ");
+       if(OggFLAC__seekable_stream_encoder_get_streamable_subset(encoder) != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo()... ");
+       if(OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo()... ");
+       if(OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_channels()... ");
+       if(OggFLAC__seekable_stream_encoder_get_channels(encoder) != streaminfo_.data.stream_info.channels) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, OggFLAC__seekable_stream_encoder_get_channels(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_bits_per_sample()... ");
+       if(OggFLAC__seekable_stream_encoder_get_bits_per_sample(encoder) != streaminfo_.data.stream_info.bits_per_sample) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, OggFLAC__seekable_stream_encoder_get_bits_per_sample(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_sample_rate()... ");
+       if(OggFLAC__seekable_stream_encoder_get_sample_rate(encoder) != streaminfo_.data.stream_info.sample_rate) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, OggFLAC__seekable_stream_encoder_get_sample_rate(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_blocksize()... ");
+       if(OggFLAC__seekable_stream_encoder_get_blocksize(encoder) != streaminfo_.data.stream_info.min_blocksize) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, OggFLAC__seekable_stream_encoder_get_blocksize(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_max_lpc_order()... ");
+       if(OggFLAC__seekable_stream_encoder_get_max_lpc_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__seekable_stream_encoder_get_max_lpc_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision()... ");
+       (void)OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder);
+       /* we asked the encoder to auto select this so we accept anything */
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search()... ");
+       if(OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_do_escape_coding()... ");
+       if(OggFLAC__seekable_stream_encoder_get_do_escape_coding(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search()... ");
+       if(OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_min_residual_partition_order()... ");
+       if(OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_max_residual_partition_order()... ");
+       if(OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist()... ");
+       if(OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_get_total_samples_estimate()... ");
+       if(OggFLAC__seekable_stream_encoder_get_total_samples_estimate(encoder) != streaminfo_.data.stream_info.total_samples) {
+               printf("FAILED, expected %llu, got %llu\n", streaminfo_.data.stream_info.total_samples, OggFLAC__seekable_stream_encoder_get_total_samples_estimate(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       /* init the dummy sample buffer */
+       for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+               samples[i] = i & 7;
+
+       printf("testing OggFLAC__seekable_stream_encoder_process()... ");
+       if(!OggFLAC__seekable_stream_encoder_process(encoder, (const FLAC__int32 * const *)samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_process_interleaved()... ");
+       if(!OggFLAC__seekable_stream_encoder_process_interleaved(encoder, samples, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_ss_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_finish()... ");
+       OggFLAC__seekable_stream_encoder_finish(encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__seekable_stream_encoder_delete()... ");
+       OggFLAC__seekable_stream_encoder_delete(encoder);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+static void file_encoder_progress_callback_(const OggFLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+{
+       (void)encoder, (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate, (void)client_data;
+}
+
+static FLAC__bool test_file_encoder()
+{
+       OggFLAC__FileEncoder *encoder;
+       OggFLAC__FileEncoderState state;
+       OggFLAC__SeekableStreamEncoderState sstate;
+       FLAC__SeekableStreamEncoderState fsstate;
+       FLAC__StreamEncoderState fstate;
+       FLAC__StreamDecoderState dstate;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1];
+       unsigned i;
+
+       samples_array[0] = samples;
+
+       printf("\n+++ libOggFLAC unit test: OggFLAC__FileEncoder\n\n");
+
+       printf("testing OggFLAC__file_encoder_new()... ");
+       encoder = OggFLAC__file_encoder_new();
+       if(0 == encoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_serial_number()... ");
+       if(!OggFLAC__file_encoder_set_serial_number(encoder, file_utils__serial_number))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_verify()... ");
+       if(!OggFLAC__file_encoder_set_verify(encoder, true))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_streamable_subset()... ");
+       if(!OggFLAC__file_encoder_set_streamable_subset(encoder, true))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_do_mid_side_stereo()... ");
+       if(!OggFLAC__file_encoder_set_do_mid_side_stereo(encoder, false))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_loose_mid_side_stereo()... ");
+       if(!OggFLAC__file_encoder_set_loose_mid_side_stereo(encoder, false))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_channels()... ");
+       if(!OggFLAC__file_encoder_set_channels(encoder, streaminfo_.data.stream_info.channels))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_bits_per_sample()... ");
+       if(!OggFLAC__file_encoder_set_bits_per_sample(encoder, streaminfo_.data.stream_info.bits_per_sample))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_sample_rate()... ");
+       if(!OggFLAC__file_encoder_set_sample_rate(encoder, streaminfo_.data.stream_info.sample_rate))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_blocksize()... ");
+       if(!OggFLAC__file_encoder_set_blocksize(encoder, streaminfo_.data.stream_info.min_blocksize))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_max_lpc_order()... ");
+       if(!OggFLAC__file_encoder_set_max_lpc_order(encoder, 0))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_qlp_coeff_precision()... ");
+       if(!OggFLAC__file_encoder_set_qlp_coeff_precision(encoder, 0))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_do_qlp_coeff_prec_search()... ");
+       if(!OggFLAC__file_encoder_set_do_qlp_coeff_prec_search(encoder, false))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_do_escape_coding()... ");
+       if(!OggFLAC__file_encoder_set_do_escape_coding(encoder, false))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_do_exhaustive_model_search()... ");
+       if(!OggFLAC__file_encoder_set_do_exhaustive_model_search(encoder, false))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_min_residual_partition_order()... ");
+       if(!OggFLAC__file_encoder_set_min_residual_partition_order(encoder, 0))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_max_residual_partition_order()... ");
+       if(!OggFLAC__file_encoder_set_max_residual_partition_order(encoder, 0))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_rice_parameter_search_dist()... ");
+       if(!OggFLAC__file_encoder_set_rice_parameter_search_dist(encoder, 0))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_total_samples_estimate()... ");
+       if(!OggFLAC__file_encoder_set_total_samples_estimate(encoder, streaminfo_.data.stream_info.total_samples))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_metadata()... ");
+       if(!OggFLAC__file_encoder_set_metadata(encoder, metadata_sequence_, num_metadata_))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_filename()... ");
+       if(!OggFLAC__file_encoder_set_filename(encoder, oggflacfilename_))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_progress_callback()... ");
+       if(!OggFLAC__file_encoder_set_progress_callback(encoder, file_encoder_progress_callback_))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_set_client_data()... ");
+       if(!OggFLAC__file_encoder_set_client_data(encoder, 0))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_init()... ");
+       if(OggFLAC__file_encoder_init(encoder) != OggFLAC__FILE_ENCODER_OK)
+               return die_f_(0, encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_state()... ");
+       state = OggFLAC__file_encoder_get_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)state, OggFLAC__FileEncoderStateString[state]);
+
+       printf("testing OggFLAC__file_encoder_get_seekable_stream_encoder_state()... ");
+       sstate = OggFLAC__file_encoder_get_seekable_stream_encoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)sstate, OggFLAC__SeekableStreamEncoderStateString[sstate]);
+
+       printf("testing OggFLAC__file_encoder_get_FLAC_seekable_stream_encoder_state()... ");
+       fsstate = OggFLAC__file_encoder_get_FLAC_seekable_stream_encoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)fsstate, FLAC__SeekableStreamEncoderStateString[fsstate]);
+
+       printf("testing OggFLAC__file_encoder_get_FLAC_stream_encoder_state()... ");
+       fstate = OggFLAC__file_encoder_get_FLAC_stream_encoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)fstate, FLAC__StreamEncoderStateString[fstate]);
+
+       printf("testing OggFLAC__file_encoder_get_verify_decoder_state()... ");
+       dstate = OggFLAC__file_encoder_get_verify_decoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+
+       {
+               FLAC__uint64 absolute_sample;
+               unsigned frame_number;
+               unsigned channel;
+               unsigned sample;
+               FLAC__int32 expected;
+               FLAC__int32 got;
+
+               printf("testing OggFLAC__file_encoder_get_verify_decoder_error_stats()... ");
+               OggFLAC__file_encoder_get_verify_decoder_error_stats(encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+               printf("OK\n");
+       }
+
+       printf("testing OggFLAC__file_encoder_get_verify()... ");
+       if(OggFLAC__file_encoder_get_verify(encoder) != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_streamable_subset()... ");
+       if(OggFLAC__file_encoder_get_streamable_subset(encoder) != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_do_mid_side_stereo()... ");
+       if(OggFLAC__file_encoder_get_do_mid_side_stereo(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_loose_mid_side_stereo()... ");
+       if(OggFLAC__file_encoder_get_loose_mid_side_stereo(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_channels()... ");
+       if(OggFLAC__file_encoder_get_channels(encoder) != streaminfo_.data.stream_info.channels) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, OggFLAC__file_encoder_get_channels(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_bits_per_sample()... ");
+       if(OggFLAC__file_encoder_get_bits_per_sample(encoder) != streaminfo_.data.stream_info.bits_per_sample) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, OggFLAC__file_encoder_get_bits_per_sample(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_sample_rate()... ");
+       if(OggFLAC__file_encoder_get_sample_rate(encoder) != streaminfo_.data.stream_info.sample_rate) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, OggFLAC__file_encoder_get_sample_rate(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_blocksize()... ");
+       if(OggFLAC__file_encoder_get_blocksize(encoder) != streaminfo_.data.stream_info.min_blocksize) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, OggFLAC__file_encoder_get_blocksize(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_max_lpc_order()... ");
+       if(OggFLAC__file_encoder_get_max_lpc_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__file_encoder_get_max_lpc_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_qlp_coeff_precision()... ");
+       (void)OggFLAC__file_encoder_get_qlp_coeff_precision(encoder);
+       /* we asked the encoder to auto select this so we accept anything */
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_do_qlp_coeff_prec_search()... ");
+       if(OggFLAC__file_encoder_get_do_qlp_coeff_prec_search(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_do_escape_coding()... ");
+       if(OggFLAC__file_encoder_get_do_escape_coding(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_do_exhaustive_model_search()... ");
+       if(OggFLAC__file_encoder_get_do_exhaustive_model_search(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_min_residual_partition_order()... ");
+       if(OggFLAC__file_encoder_get_min_residual_partition_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__file_encoder_get_min_residual_partition_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_max_residual_partition_order()... ");
+       if(OggFLAC__file_encoder_get_max_residual_partition_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__file_encoder_get_max_residual_partition_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_rice_parameter_search_dist()... ");
+       if(OggFLAC__file_encoder_get_rice_parameter_search_dist(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, OggFLAC__file_encoder_get_rice_parameter_search_dist(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_get_total_samples_estimate()... ");
+       if(OggFLAC__file_encoder_get_total_samples_estimate(encoder) != streaminfo_.data.stream_info.total_samples) {
+               printf("FAILED, expected %llu, got %llu\n", streaminfo_.data.stream_info.total_samples, OggFLAC__file_encoder_get_total_samples_estimate(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       /* init the dummy sample buffer */
+       for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+               samples[i] = i & 7;
+
+       printf("testing OggFLAC__file_encoder_process()... ");
+       if(!OggFLAC__file_encoder_process(encoder, (const FLAC__int32 * const *)samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_process_interleaved()... ");
+       if(!OggFLAC__file_encoder_process_interleaved(encoder, samples, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_f_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_finish()... ");
+       OggFLAC__file_encoder_finish(encoder);
+       printf("OK\n");
+
+       printf("testing OggFLAC__file_encoder_delete()... ");
+       OggFLAC__file_encoder_delete(encoder);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
 FLAC__bool test_encoders()
 {
        init_metadata_blocks_();
@@ -388,6 +1101,12 @@ FLAC__bool test_encoders()
        if(!test_stream_encoder())
                return false;
 
+       if(!test_seekable_stream_encoder())
+               return false;
+
+       if(!test_file_encoder())
+               return false;
+
        (void) grabbag__file_remove_file(oggflacfilename_);
        free_metadata_blocks_();