massive glob of checkins: improved tests, more tests, bugfixes
authorJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 7 Jun 2002 05:27:37 +0000 (05:27 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 7 Jun 2002 05:27:37 +0000 (05:27 +0000)
68 files changed:
Makefile.lite
configure.in
flac.pbproj/project.pbxproj
include/FLAC++/decoder.h
include/FLAC++/encoder.h
include/FLAC++/metadata.h
include/FLAC/file_decoder.h
include/FLAC/format.h
include/FLAC/metadata.h
include/FLAC/seekable_stream_decoder.h
include/FLAC/stream_decoder.h
include/FLAC/stream_encoder.h
src/Makefile.am
src/flac/decode.c
src/flac/encode.c
src/libFLAC++/Makefile.am
src/libFLAC++/file_decoder.cc
src/libFLAC++/metadata.cc
src/libFLAC++/seekable_stream_decoder.cc
src/libFLAC++/stream_decoder.cc
src/libFLAC++/stream_encoder.cc
src/libFLAC/Makefile.am
src/libFLAC/file_decoder.c
src/libFLAC/format.c
src/libFLAC/include/private/md5.h
src/libFLAC/md5.c
src/libFLAC/metadata_iterators.c
src/libFLAC/metadata_object.c
src/libFLAC/seekable_stream_decoder.c
src/libFLAC/stream_decoder.c
src/libFLAC/stream_encoder.c
src/plugin_winamp2/in_flac.c
src/plugin_xmms/plugin.c
src/test_libFLAC++/Makefile.am [new file with mode: 0644]
src/test_libFLAC++/Makefile.lite [new file with mode: 0644]
src/test_libFLAC++/Makefile.vc [new file with mode: 0644]
src/test_libFLAC++/README [new file with mode: 0644]
src/test_libFLAC++/decoders.cc [new file with mode: 0644]
src/test_libFLAC++/decoders.h [new file with mode: 0644]
src/test_libFLAC++/encoders.cc [new file with mode: 0644]
src/test_libFLAC++/encoders.h [new file with mode: 0644]
src/test_libFLAC++/file_utils.c [new file with mode: 0644]
src/test_libFLAC++/file_utils.h [new file with mode: 0644]
src/test_libFLAC++/main.cc [new file with mode: 0644]
src/test_libFLAC++/metadata.cc [new file with mode: 0644]
src/test_libFLAC++/metadata.h [new file with mode: 0644]
src/test_libFLAC++/metadata_manip.cc [new file with mode: 0644]
src/test_libFLAC++/metadata_object.cc [new file with mode: 0644]
src/test_unit/Makefile.am
src/test_unit/Makefile.lite
src/test_unit/Makefile.vc
src/test_unit/bitbuffer.c
src/test_unit/bitbuffer.h
src/test_unit/decoders.c
src/test_unit/decoders.h
src/test_unit/encoders.c [new file with mode: 0644]
src/test_unit/encoders.h [new file with mode: 0644]
src/test_unit/file_utils.c
src/test_unit/file_utils.h
src/test_unit/main.c
src/test_unit/metadata.c
src/test_unit/metadata.h
src/test_unit/metadata_manip.c
src/test_unit/metadata_object.c
src/test_unit/metadata_utils.c
src/test_unit/metadata_utils.h
test/Makefile.am
test/Makefile.lite

index 65acab0..729167b 100644 (file)
@@ -27,7 +27,7 @@
 # clean   : remove all non-distro files
 #
 
-all: libFLAC libFLAC++ share flac metaflac test_streams test_unit
+all: libFLAC libFLAC++ share flac metaflac test_libFLAC test_libFLAC++ test_streams
 
 DEFAULT_CONFIG = release
 
@@ -42,7 +42,7 @@ release : all
 libFLAC:
        (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
 
-libFLAC++: libFLAC
+libFLAC++:
        (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
 
 share:
@@ -51,7 +51,7 @@ share:
 flac: libFLAC
        (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
 
-metaflac:
+metaflac: libFLAC share
        (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
 
 plugin_xmms: libFLAC
@@ -60,7 +60,10 @@ plugin_xmms: libFLAC
 test_streams: libFLAC
        (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
 
-test_unit: libFLAC
+test_libFLAC: libFLAC
+       (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+test_libFLAC++: libFLAC libFLAC++
        (cd src/$@ ; $(MAKE) -f Makefile.lite $(CONFIG))
 
 test: debug
@@ -73,6 +76,7 @@ clean:
        -(cd src/flac ; $(MAKE) -f Makefile.lite clean)
        -(cd src/metaflac ; $(MAKE) -f Makefile.lite clean)
        -(cd src/plugin_xmms ; $(MAKE) -f Makefile.lite clean)
+       -(cd src/test_libFLAC ; $(MAKE) -f Makefile.lite clean)
+       -(cd src/test_libFLAC++ ; $(MAKE) -f Makefile.lite clean)
        -(cd src/test_streams ; $(MAKE) -f Makefile.lite clean)
-       -(cd src/test_unit ; $(MAKE) -f Makefile.lite clean)
        -(cd test ; $(MAKE) -f Makefile.lite clean)
index 700b117..66af86c 100644 (file)
@@ -28,6 +28,7 @@ AM_PROG_LIBTOOL
 sed -e 's/^build_old_libs=yes/build_old_libs=no/' libtool > libtool-disable-static
 chmod +x libtool-disable-static
 
+AC_PROG_CXX
 AC_PROG_MAKE_SET
 
 dnl check for getopt in standard library
@@ -163,17 +164,17 @@ AC_SUBST(FLaC__USIZE64)
 
 AC_SUBST(SHARE_LIBS)
 
-SAVE_CFLAGS="$CFLAGS"
-CFLAGS='-I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include'
+OUR_CFLAGS_HEAD='-I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include'
 if test x$debug = xtrue; then
-       CFLAGS="$CFLAGS -g -O0 -DDEBUG"
+       OUR_CFLAGS_TAIL="-g -O0 -DDEBUG"
 else
-       CFLAGS="$CFLAGS -O3 -DNDEBUG"
+       OUR_CFLAGS_TAIL="-O3 -DNDEBUG"
        if test x$GCC = xyes; then
-               CFLAGS="$CFLAGS -fomit-frame-pointer -funroll-loops -finline-functions -Wall -W -Winline -DFLaC__INLINE=__inline__"
+               OUR_CFLAGS_TAIL="$OUR_CFLAGS_TAIL -fomit-frame-pointer -funroll-loops -finline-functions -Wall -W -Winline -DFLaC__INLINE=__inline__"
        fi
 fi
-CFLAGS="$CFLAGS $SAVE_CFLAGS"
+CFLAGS="$OUR_CFLAGS_HEAD $CFLAGS $OUR_CFLAGS_TAIL"
+CXXFLAGS="$OUR_CFLAGS_HEAD $CXXFLAGS $OUR_CFLAGS_TAIL"
 
 AC_OUTPUT(     Makefile        \
        src/Makefile    \
@@ -182,12 +183,14 @@ AC_OUTPUT(        Makefile        \
        src/libFLAC/include/Makefile    \
        src/libFLAC/include/private/Makefile    \
        src/libFLAC/include/protected/Makefile  \
+       src/libFLAC++/Makefile  \
        src/flac/Makefile       \
        src/metaflac/Makefile   \
        src/plugin_xmms/Makefile        \
        src/share/Makefile      \
+       src/test_libFLAC/Makefile       \
+       src/test_libFLAC++/Makefile     \
        src/test_streams/Makefile       \
-       src/test_unit/Makefile  \
        include/Makefile \
        include/FLAC/Makefile \
        include/FLAC/ordinals.h \
index 75986d9..c9b93a0 100644 (file)
                                F59E59BF01972D3E01A8006D,
                        );
                        isa = PBXGroup;
-                       path = test_unit;
+                       path = test_libFLAC;
                        refType = 4;
                };
                F59E59BD01972D3E01A8006D = {
                };
                F5F561EF019B58E101A8006D = {
                        isa = PBXExecutableFileReference;
-                       path = test_unit;
+                       path = test_libFLAC;
                        refType = 3;
                };
                F5F561F0019B58E101A8006D = {
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = test_unit;
+                               PRODUCT_NAME = test_libFLAC;
                                REZ_EXECUTABLE = YES;
                                SECTORDER_FLAGS = "";
                                WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
                        dependencies = (
                        );
                        isa = PBXToolTarget;
-                       name = test_unit;
+                       name = test_libFLAC;
                        productInstallPath = /usr/local/bin;
-                       productName = test_unit;
+                       productName = test_libFLAC;
                        productReference = F5F561EF019B58E101A8006D;
                        shouldUseHeadermap = 0;
                };
index 02c8992..4d29cb6 100644 (file)
@@ -98,14 +98,14 @@ namespace FLAC {
                        bool process_remaining_frames();
                protected:
                        virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes) = 0;
-                       virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *buffer[]) = 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;
 
                        ::FLAC__StreamDecoder *decoder_;
                private:
                        static ::FLAC__StreamDecoderReadStatus read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
-                       static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+                       static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
                        static void metadata_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__StreamMetaData *metadata, void *client_data);
                        static void error_callback_(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data);
 
@@ -172,7 +172,7 @@ namespace FLAC {
                        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 *buffer[]) = 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;
 
@@ -183,7 +183,7 @@ namespace FLAC {
                        static FLAC__SeekableStreamDecoderTellStatus tell_callback_(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
                        static FLAC__SeekableStreamDecoderLengthStatus length_callback_(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
                        static FLAC__bool eof_callback_(const ::FLAC__SeekableStreamDecoder *decoder, void *client_data);
-                       static FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+                       static FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
                        static void metadata_callback_(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetaData *metadata, void *client_data);
                        static void error_callback_(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data);
 
@@ -243,13 +243,13 @@ namespace FLAC {
 
                        bool seek_absolute(FLAC__uint64 sample);
                protected:
-                       virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *buffer[]) = 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;
 
                        ::FLAC__FileDecoder *decoder_;
                private:
-                       static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__FileDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+                       static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__FileDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
                        static void metadata_callback_(const ::FLAC__FileDecoder *decoder, const ::FLAC__StreamMetaData *metadata, void *client_data);
                        static void error_callback_(const ::FLAC__FileDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data);
 
index 071ff7f..69005fa 100644 (file)
@@ -80,7 +80,7 @@ namespace FLAC {
                        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_metadata(::FLAC__StreamMetaData **metadata, unsigned num_blocks);
 
                        State    get_state() const;
                        bool     get_streamable_subset() const;
@@ -106,11 +106,11 @@ namespace FLAC {
 
                        void finish();
 
-                       bool process(const FLAC__int32 *buf[], unsigned samples);
-                       bool process_interleaved(const FLAC__int32 buf[], unsigned samples);
+                       bool process(const FLAC__int32 * const buffer[], unsigned samples);
+                       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;
 
                        ::FLAC__StreamEncoder *encoder_;
                private:
index 7e0cbbd..fa74188 100644 (file)
@@ -47,21 +47,28 @@ namespace FLAC {
                class Prototype {
                protected:
                        Prototype(::FLAC__StreamMetaData *object, bool copy);
-                       virtual ~Prototype();
 
                        void operator=(const Prototype &);
                        void operator=(const ::FLAC__StreamMetaData &);
                        void operator=(const ::FLAC__StreamMetaData *);
 
+                       inline bool operator==(const Prototype &) const;
+                       inline bool operator==(const ::FLAC__StreamMetaData &) const;
+                       inline bool operator==(const ::FLAC__StreamMetaData *) const;
+                       inline bool operator!=(const Prototype &) const;
+                       inline bool operator!=(const ::FLAC__StreamMetaData &) const;
+                       inline bool operator!=(const ::FLAC__StreamMetaData *) const;
+
                        virtual void clear();
 
                        ::FLAC__StreamMetaData *object_;
                public:
+                       virtual ~Prototype();
+
                        friend class SimpleIterator;
                        friend class Iterator;
 
-                       inline bool is_valid() const { return 0 != object_; }
-                       inline operator bool() const { return is_valid(); }
+                       inline bool is_valid() const;
 
                        bool get_is_last() const;
                        FLAC__MetaDataType get_type() const;
@@ -74,6 +81,28 @@ namespace FLAC {
                        inline void set_reference(bool x) { is_reference_ = x; }
                };
 
+               inline bool Prototype::operator==(const Prototype &object) const 
+               { return ::FLAC__metadata_object_is_equal(object_, object.object_); }
+
+               inline bool Prototype::operator==(const ::FLAC__StreamMetaData &object) const 
+               { return ::FLAC__metadata_object_is_equal(object_, &object); }
+
+               inline bool Prototype::operator==(const ::FLAC__StreamMetaData *object) const 
+               { return ::FLAC__metadata_object_is_equal(object_, object); }
+
+               inline bool Prototype::operator!=(const Prototype &object) const 
+               { return !operator==(object); }
+
+               inline bool Prototype::operator!=(const ::FLAC__StreamMetaData &object) const 
+               { return !operator==(object); }
+
+               inline bool Prototype::operator!=(const ::FLAC__StreamMetaData *object) const 
+               { return !operator==(object); }
+
+               inline bool Prototype::is_valid() const
+               { return 0 != object_; }
+
+
                class StreamInfo : public Prototype {
                public:
                        StreamInfo();
@@ -84,6 +113,13 @@ namespace FLAC {
                        inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
                        inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
 
+                       inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+
                        unsigned get_min_blocksize() const;
                        unsigned get_max_blocksize() const;
                        unsigned get_min_framesize() const;
@@ -115,6 +151,13 @@ namespace FLAC {
                        inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
                        inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
 
+                       inline bool operator==(const Padding &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const Padding &object) const { return Prototype::operator!=(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+
                        void set_length(unsigned length);
                };
 
@@ -128,6 +171,13 @@ namespace FLAC {
                        inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
                        inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
 
+                       inline bool operator==(const Application &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const Application &object) const { return Prototype::operator!=(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+
                        const FLAC__byte *get_id() const;
                        const FLAC__byte *get_data() const;
 
@@ -145,6 +195,13 @@ namespace FLAC {
                        inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
                        inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
 
+                       inline bool operator==(const SeekTable &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const SeekTable &object) const { return Prototype::operator!=(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+
                        unsigned get_num_points() const;
                        ::FLAC__StreamMetaData_SeekPoint get_point(unsigned index) const;
 
@@ -168,7 +225,6 @@ namespace FLAC {
                                virtual ~Entry();
 
                                virtual bool is_valid() const;
-                               inline operator bool() const { return is_valid(); }
 
                                unsigned get_field_length() const;
                                unsigned get_field_name_length() const;
@@ -209,6 +265,13 @@ namespace FLAC {
                        inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
                        inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
 
+                       inline bool operator==(const VorbisComment &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator==(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const VorbisComment &object) const { return Prototype::operator!=(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData &object) const { return Prototype::operator==(object); }
+                       inline bool operator!=(const ::FLAC__StreamMetaData *object) const { return Prototype::operator==(object); }
+
                        unsigned get_num_comments() const;
                        Entry get_vendor_string() const;
                        Entry get_comment(unsigned index) const;
@@ -274,7 +337,6 @@ namespace FLAC {
                        bool init(const char *filename, bool preserve_file_stats = false);
 
                        bool is_valid() const;
-                       inline operator bool() const { return is_valid(); }
                        Status status();
                        bool is_writable() const;
 
@@ -347,7 +409,6 @@ namespace FLAC {
                        friend class Iterator;
 
                        bool is_valid() const;
-                       inline operator bool() const { return is_valid(); }
                        Status status();
 
                        bool read(const char *filename);
@@ -367,7 +428,6 @@ namespace FLAC {
                        virtual ~Iterator();
 
                        bool is_valid() const;
-                       inline operator bool() const { return is_valid(); }
 
                        void init(Chain *chain);
 
index 2771948..c3dc22e 100644 (file)
@@ -37,7 +37,7 @@ typedef enum {
     FLAC__FILE_DECODER_INVALID_CALLBACK,
     FLAC__FILE_DECODER_UNINITIALIZED
 } FLAC__FileDecoderState;
-extern const char *FLAC__FileDecoderStateString[];
+extern const char * const FLAC__FileDecoderStateString[];
 
 /***********************************************************************
  *
@@ -99,7 +99,7 @@ void FLAC__file_decoder_delete(FLAC__FileDecoder *);
  */
 FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value);
 FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value); /* 'value' may not be 0; use "-" for stdin */
-FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data));
+FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data));
 FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, void (*value)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data));
 FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, void (*value)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data));
 FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value);
index 141c8a1..babe687 100644 (file)
@@ -84,7 +84,7 @@ extern const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */;
 typedef enum {
        FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0
 } FLAC__EntropyCodingMethodType;
-extern const char *FLAC__EntropyCodingMethodTypeString[];
+extern const char * const FLAC__EntropyCodingMethodTypeString[];
 
 /*****************************************************************************
  *
@@ -126,7 +126,7 @@ typedef enum {
        FLAC__SUBFRAME_TYPE_FIXED = 2,
        FLAC__SUBFRAME_TYPE_LPC = 3
 } FLAC__SubframeType;
-extern const char *FLAC__SubframeTypeString[];
+extern const char * const FLAC__SubframeTypeString[];
 
 /*****************************************************************************
  *
@@ -233,13 +233,13 @@ typedef enum {
        FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2,
        FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3
 } FLAC__ChannelAssignment;
-extern const char *FLAC__ChannelAssignmentString[];
+extern const char * const FLAC__ChannelAssignmentString[];
 
 typedef enum {
        FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER,
        FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER
 } FLAC__FrameNumberType;
-extern const char *FLAC__FrameNumberTypeString[];
+extern const char * const FLAC__FrameNumberTypeString[];
 
 /*****************************************************************************
  *
@@ -351,7 +351,7 @@ typedef enum {
        FLAC__METADATA_TYPE_SEEKTABLE = 3,
        FLAC__METADATA_TYPE_VORBIS_COMMENT = 4
 } FLAC__MetaDataType;
-extern const char *FLAC__MetaDataTypeString[];
+extern const char * const FLAC__MetaDataTypeString[];
 
 /*****************************************************************************
  *
index 021a4c9..a42068f 100644 (file)
@@ -24,7 +24,7 @@
 
 /******************************************************************************
        (For an example of how all these routines are used, see the source
-       code for the unit tests in src/test_unit/metadata_*.c, or metaflac
+       code for the unit tests in src/test_libFLAC/metadata_*.c, or metaflac
        in src/metaflac/)
 ******************************************************************************/
 
@@ -146,7 +146,7 @@ typedef enum {
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR,
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR
 } FLAC__MetaData_SimpleIteratorStatus;
-extern const char *FLAC__MetaData_SimpleIteratorStatusString[];
+extern const char * const FLAC__MetaData_SimpleIteratorStatusString[];
 
 /*
  * Constructor/destructor
@@ -335,7 +335,7 @@ typedef enum {
        FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR,
        FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR
 } FLAC__MetaData_ChainStatus;
-extern const char *FLAC__MetaData_ChainStatusString[];
+extern const char * const FLAC__MetaData_ChainStatusString[];
 
 /*********** FLAC__MetaData_Chain ***********/
 
@@ -518,6 +518,8 @@ FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__MetaData_Iterator *i
 FLAC__StreamMetaData *FLAC__metadata_object_new(FLAC__MetaDataType type);
 FLAC__StreamMetaData *FLAC__metadata_object_copy(const FLAC__StreamMetaData *object);
 void FLAC__metadata_object_delete(FLAC__StreamMetaData *object);
+/* Does a deep comparison of the block data */
+FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetaData *block1, const FLAC__StreamMetaData *block2);
 
 /******************************************************************
  * FLAC__StreamMetaData_Application
index fa88764..7d69792 100644 (file)
@@ -39,31 +39,31 @@ typedef enum {
     FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK,
     FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED
 } FLAC__SeekableStreamDecoderState;
-extern const char *FLAC__SeekableStreamDecoderStateString[];
+extern const char * const FLAC__SeekableStreamDecoderStateString[];
 
 typedef enum {
        FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK,
        FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR
 } FLAC__SeekableStreamDecoderReadStatus;
-extern const char *FLAC__SeekableStreamDecoderReadStatusString[];
+extern const char * const FLAC__SeekableStreamDecoderReadStatusString[];
 
 typedef enum {
        FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK,
        FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
 } FLAC__SeekableStreamDecoderSeekStatus;
-extern const char *FLAC__SeekableStreamDecoderSeekStatusString[];
+extern const char * const FLAC__SeekableStreamDecoderSeekStatusString[];
 
 typedef enum {
        FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK,
        FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
 } FLAC__SeekableStreamDecoderTellStatus;
-extern const char *FLAC__SeekableStreamDecoderTellStatusString[];
+extern const char * const FLAC__SeekableStreamDecoderTellStatusString[];
 
 typedef enum {
        FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK,
        FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
 } FLAC__SeekableStreamDecoderLengthStatus;
-extern const char *FLAC__SeekableStreamDecoderLengthStatusString[];
+extern const char * const FLAC__SeekableStreamDecoderLengthStatusString[];
 
 /***********************************************************************
  *
@@ -134,7 +134,7 @@ FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamD
 FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellStatus (*value)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data));
 FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthStatus (*value)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data));
 FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__bool (*value)(const FLAC__SeekableStreamDecoder *decoder, void *client_data));
-FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data));
+FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data));
 FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, void (*value)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data));
 FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, void (*value)(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data));
 FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value);
index 90d8eb2..e2cb349 100644 (file)
@@ -40,27 +40,27 @@ typedef enum {
        FLAC__STREAM_DECODER_INVALID_CALLBACK,
        FLAC__STREAM_DECODER_UNINITIALIZED
 } FLAC__StreamDecoderState;
-extern const char *FLAC__StreamDecoderStateString[];
+extern const char * const FLAC__StreamDecoderStateString[];
 
 typedef enum {
        FLAC__STREAM_DECODER_READ_STATUS_CONTINUE,
        FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM,
        FLAC__STREAM_DECODER_READ_STATUS_ABORT
 } FLAC__StreamDecoderReadStatus;
-extern const char *FLAC__StreamDecoderReadStatusString[];
+extern const char * const FLAC__StreamDecoderReadStatusString[];
 
 typedef enum {
        FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
        FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
 } FLAC__StreamDecoderWriteStatus;
-extern const char *FLAC__StreamDecoderWriteStatusString[];
+extern const char * const FLAC__StreamDecoderWriteStatusString[];
 
 typedef enum {
        FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
        FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
        FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH
 } FLAC__StreamDecoderErrorStatus;
-extern const char *FLAC__StreamDecoderErrorStatusString[];
+extern const char * const FLAC__StreamDecoderErrorStatusString[];
 
 /***********************************************************************
  *
@@ -121,7 +121,7 @@ void FLAC__stream_decoder_delete(FLAC__StreamDecoder *);
 @@@@ update defaults above and in documentation.html about the metadata_respond/ignore defaults
  */
 FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadStatus (*value)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data));
-FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data));
+FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data));
 FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, void (*value)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data));
 FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, void (*value)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data));
 FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value);
index 9c0a013..2278a38 100644 (file)
@@ -48,13 +48,13 @@ typedef enum {
        FLAC__STREAM_ENCODER_ALREADY_INITIALIZED,
        FLAC__STREAM_ENCODER_UNINITIALIZED
 } FLAC__StreamEncoderState;
-extern const char *FLAC__StreamEncoderStateString[];
+extern const char * const FLAC__StreamEncoderStateString[];
 
 typedef enum {
        FLAC__STREAM_ENCODER_WRITE_OK = 0,
        FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR
 } FLAC__StreamEncoderWriteStatus;
-extern const char *FLAC__StreamEncoderWriteStatusString[];
+extern const char * const FLAC__StreamEncoderWriteStatusString[];
 
 /***********************************************************************
  *
@@ -189,8 +189,8 @@ void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
 /*
  * Methods for encoding the data
  */
-FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 *buf[], unsigned samples);
-FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buf[], unsigned samples);
+FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
 
 #ifdef __cplusplus
 }
index 6713853..49762f9 100644 (file)
@@ -19,4 +19,4 @@ if FLaC__HAS_XMMS
 XMMS_DIRS = plugin_xmms
 endif
 
-SUBDIRS = libFLAC libFLAC++ share flac metaflac $(XMMS_DIRS) test_streams test_unit
+SUBDIRS = libFLAC libFLAC++ share flac metaflac $(XMMS_DIRS) test_libFLAC test_libFLAC++ test_streams
index 3dcd292..5d60dc9 100644 (file)
@@ -518,10 +518,9 @@ FLAC__bool init(const char *infilename, stream_info_struct *stream_info)
                FLAC__file_decoder_set_filename(stream_info->decoder.file, infilename);
                /*
                 * The three ugly casts here are to 'downcast' the 'void *' argument of
-                * the callback down to 'FLAC__FileDecoder *'.  In C++ this would be
-                * unnecessary but here the cast makes the C compiler happy.
+                * the callback down to 'FLAC__FileDecoder *'.
                 */
-               FLAC__file_decoder_set_write_callback(stream_info->decoder.file, (FLAC__StreamDecoderWriteStatus (*)(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 *[], void *))write_callback);
+               FLAC__file_decoder_set_write_callback(stream_info->decoder.file, (FLAC__StreamDecoderWriteStatus (*)(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 * const [], void *))write_callback);
                FLAC__file_decoder_set_metadata_callback(stream_info->decoder.file, (void (*)(const FLAC__FileDecoder *, const FLAC__StreamMetaData *, void *))metadata_callback);
                FLAC__file_decoder_set_error_callback(stream_info->decoder.file, (void (*)(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
                FLAC__file_decoder_set_client_data(stream_info->decoder.file, stream_info);
index 9be92fb..a2ad9bd 100644 (file)
@@ -111,11 +111,11 @@ static FLAC__bool convert_to_seek_table(char *requested_seek_points, int num_req
 static void append_point_to_seek_table(FLAC__StreamMetaData_SeekTable *seek_table, FLAC__uint64 sample, FLAC__uint64 stream_samples, FLAC__uint64 blocksize);
 static int seekpoint_compare(const FLAC__StreamMetaData_SeekPoint *l, const FLAC__StreamMetaData_SeekPoint *r);
 static void format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, encoder_wrapper_struct *encoder_wrapper);
-static void append_to_verify_fifo(encoder_wrapper_struct *encoder_wrapper, const FLAC__int32 *input[], unsigned channels, unsigned wide_samples);
+static void append_to_verify_fifo(encoder_wrapper_struct *encoder_wrapper, const FLAC__int32 * const input[], unsigned channels, unsigned wide_samples);
 static FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
 static void metadata_callback(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data);
 static FLAC__StreamDecoderReadStatus verify_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
-static FLAC__StreamDecoderWriteStatus verify_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+static FLAC__StreamDecoderWriteStatus verify_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
 static void verify_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
 static void verify_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 static void print_stats(const encoder_wrapper_struct *encoder_wrapper);
@@ -311,11 +311,9 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                 * first do any samples in the reservoir
                                 */
                                if(options.sector_align && *options.align_reservoir_samples > 0) {
-                                       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                       append_to_verify_fifo(&encoder_wrapper, options.align_reservoir, channels, *options.align_reservoir_samples);
+                                       append_to_verify_fifo(&encoder_wrapper, (const FLAC__int32 * const *)options.align_reservoir, channels, *options.align_reservoir_samples);
 
-                                       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, options.align_reservoir, *options.align_reservoir_samples)) {
+                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, (const FLAC__int32 * const *)options.align_reservoir, *options.align_reservoir_samples)) {
                                                fprintf(stderr, "%s: ERROR during encoding, state = %d:%s\n", encoder_wrapper.inbasefilename, FLAC__stream_encoder_get_state(encoder_wrapper.encoder), FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder_wrapper.encoder)]);
                                                goto wav_abort_;
                                        }
@@ -358,8 +356,7 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                                        unsigned wide_samples = bytes_read / bytes_per_wide_sample;
                                                        format_input(input, wide_samples, false, is_unsigned_samples, channels, bps, &encoder_wrapper);
 
-                                                       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, input, wide_samples)) {
+                                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, (const FLAC__int32 * const *)input, wide_samples)) {
                                                                fprintf(stderr, "%s: ERROR during encoding, state = %d:%s\n", encoder_wrapper.inbasefilename, FLAC__stream_encoder_get_state(encoder_wrapper.encoder), FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder_wrapper.encoder)]);
                                                                goto wav_abort_;
                                                        }
@@ -381,11 +378,9 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                                        data_bytes = wide_samples * bytes_per_wide_sample;
                                                        for(channel = 0; channel < channels; channel++)
                                                                memset(input[channel], 0, data_bytes);
-                                                       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                                       append_to_verify_fifo(&encoder_wrapper, input, channels, wide_samples);
+                                                       append_to_verify_fifo(&encoder_wrapper, (const FLAC__int32 * const *)input, channels, wide_samples);
 
-                                                       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, input, wide_samples)) {
+                                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, (const FLAC__int32 * const *)input, wide_samples)) {
                                                                fprintf(stderr, "%s: ERROR during encoding, state = %d:%s\n", encoder_wrapper.inbasefilename, FLAC__stream_encoder_get_state(encoder_wrapper.encoder), FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder_wrapper.encoder)]);
                                                                goto wav_abort_;
                                                        }
@@ -596,8 +591,7 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
                        unsigned wide_samples = bytes_read / bytes_per_wide_sample;
                        format_input(input, wide_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, &encoder_wrapper);
 
-                       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, input, wide_samples)) {
+                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, (const FLAC__int32 * const *)input, wide_samples)) {
                                fprintf(stderr, "%s: ERROR during encoding, state = %d:%s\n", encoder_wrapper.inbasefilename, FLAC__stream_encoder_get_state(encoder_wrapper.encoder), FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder_wrapper.encoder)]);
                                goto raw_abort_;
                        }
@@ -960,16 +954,15 @@ void format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_
                FLAC__ASSERT(0);
        }
 
-       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-       append_to_verify_fifo(encoder_wrapper, dest, channels, wide_samples);
+       append_to_verify_fifo(encoder_wrapper, (const FLAC__int32 * const *)dest, channels, wide_samples);
 }
 
-void append_to_verify_fifo(encoder_wrapper_struct *encoder_wrapper, const FLAC__int32 *src[], unsigned channels, unsigned wide_samples)
+void append_to_verify_fifo(encoder_wrapper_struct *encoder_wrapper, const FLAC__int32 * const input[], unsigned channels, unsigned wide_samples)
 {
        if(encoder_wrapper->verify) {
                unsigned channel;
                for(channel = 0; channel < channels; channel++)
-                       memcpy(&encoder_wrapper->verify_fifo.original[channel][encoder_wrapper->verify_fifo.tail], src[channel], sizeof(FLAC__int32) * wide_samples);
+                       memcpy(&encoder_wrapper->verify_fifo.original[channel][encoder_wrapper->verify_fifo.tail], input[channel], sizeof(FLAC__int32) * wide_samples);
                encoder_wrapper->verify_fifo.tail += wide_samples;
                FLAC__ASSERT(encoder_wrapper->verify_fifo.tail <= encoder_wrapper->verify_fifo.size);
        }
@@ -1197,7 +1190,7 @@ FLAC__StreamDecoderReadStatus verify_read_callback(const FLAC__StreamDecoder *de
        return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
 }
 
-FLAC__StreamDecoderWriteStatus verify_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+FLAC__StreamDecoderWriteStatus verify_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
        encoder_wrapper_struct *encoder_wrapper = (encoder_wrapper_struct *)client_data;
        unsigned channel, l, r;
index 126070b..d760257 100644 (file)
 #  Boston, MA  02111-1307, USA.
 
 lib_LTLIBRARIES = libFLAC++.la
-CFLAGS = @CFLAGS@
+CXXFLAGS = @CXXFLAGS@
 
-#@@@@ fix this
-libFLAC++_la_LDFLAGS = -version-info 2:1:1
+# see 'http://www.gnu.org/software/libtool/manual.html#Versioning' for numbering convention
+libFLAC___la_LDFLAGS = -version-info 1:0:0
 
-libFLAC++_la_SOURCES = \
+libFLAC___la_SOURCES = \
        file_decoder.cc \
        metadata.cc \
        seekable_stream_decoder.cc \
index 86d1519..abb5ac2 100644 (file)
@@ -176,7 +176,7 @@ namespace FLAC {
                        return (bool)::FLAC__file_decoder_seek_absolute(decoder_, sample);
                }
 
-               ::FLAC__StreamDecoderWriteStatus File::write_callback_(const ::FLAC__FileDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+               ::FLAC__StreamDecoderWriteStatus File::write_callback_(const ::FLAC__FileDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
                {
                        (void) decoder;
                        FLAC__ASSERT(0 != client_data);
index 8dc3f09..d1e8272 100644 (file)
@@ -61,7 +61,8 @@ namespace FLAC {
                // Prototype
                //
 
-               Prototype::Prototype(::FLAC__StreamMetaData *object, bool copy)
+               Prototype::Prototype(::FLAC__StreamMetaData *object, bool copy):
+               object_(0)
                {
                        FLAC__ASSERT(0 != object);
                        clear();
index cd1f529..c12b7c3 100644 (file)
@@ -232,7 +232,7 @@ namespace FLAC {
                        return instance->eof_callback();
                }
 
-               FLAC__StreamDecoderWriteStatus SeekableStream::write_callback_(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+               FLAC__StreamDecoderWriteStatus SeekableStream::write_callback_(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
                {
                        (void) decoder;
                        FLAC__ASSERT(0 != client_data);
index efa1206..faa7ece 100644 (file)
@@ -174,7 +174,7 @@ namespace FLAC {
                        return instance->read_callback(buffer, bytes);
                }
 
-               ::FLAC__StreamDecoderWriteStatus Stream::write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+               ::FLAC__StreamDecoderWriteStatus Stream::write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
                {
                        (void)decoder;
                        FLAC__ASSERT(0 != client_data);
index 5b87d2f..b756cb0 100644 (file)
@@ -136,7 +136,7 @@ namespace FLAC {
                        return (bool)::FLAC__stream_encoder_set_total_samples_estimate(encoder_, value);
                }
 
-               bool Stream::set_metadata(FLAC__StreamMetaData **metadata, unsigned num_blocks)
+               bool Stream::set_metadata(::FLAC__StreamMetaData **metadata, unsigned num_blocks)
                {
                        FLAC__ASSERT(is_valid());
                        return (bool)::FLAC__stream_encoder_set_metadata(encoder_, metadata, num_blocks);
@@ -241,9 +241,9 @@ namespace FLAC {
                Stream::State Stream::init()
                {
                        FLAC__ASSERT(is_valid());
-                       FLAC__stream_encoder_set_write_callback(encoder_, write_callback_);
-                       FLAC__stream_encoder_set_metadata_callback(encoder_, metadata_callback_);
-                       FLAC__stream_encoder_set_client_data(encoder_, (void*)this);
+                       ::FLAC__stream_encoder_set_write_callback(encoder_, write_callback_);
+                       ::FLAC__stream_encoder_set_metadata_callback(encoder_, metadata_callback_);
+                       ::FLAC__stream_encoder_set_client_data(encoder_, (void*)this);
                        return State(::FLAC__stream_encoder_init(encoder_));
                }
 
@@ -253,16 +253,16 @@ namespace FLAC {
                        ::FLAC__stream_encoder_finish(encoder_);
                }
 
-               bool Stream::process(const FLAC__int32 *buf[], unsigned samples)
+               bool Stream::process(const FLAC__int32 * const buffer[], unsigned samples)
                {
                        FLAC__ASSERT(is_valid());
-                       return (bool)::FLAC__stream_encoder_process(encoder_, buf, samples);
+                       return (bool)::FLAC__stream_encoder_process(encoder_, buffer, samples);
                }
 
-               bool Stream::process_interleaved(const FLAC__int32 buf[], unsigned samples)
+               bool Stream::process_interleaved(const FLAC__int32 buffer[], unsigned samples)
                {
                        FLAC__ASSERT(is_valid());
-                       return (bool)::FLAC__stream_encoder_process_interleaved(encoder_, buf, samples);
+                       return (bool)::FLAC__stream_encoder_process_interleaved(encoder_, buffer, samples);
                }
 
                ::FLAC__StreamEncoderWriteStatus Stream::write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
index 7da99d3..24c5b37 100644 (file)
@@ -34,8 +34,8 @@ endif
 
 SUBDIRS = $(ARCH_SUBDIRS) include .
 
-#@@@@ fix this
-libFLAC_la_LDFLAGS = -version-info 2:1:1
+# see 'http://www.gnu.org/software/libtool/manual.html#Versioning' for numbering convention
+libFLAC_la_LDFLAGS = -version-info 3:0:0
 
 libFLAC_la_SOURCES = \
        bitbuffer.c \
index 21224a0..62a926d 100644 (file)
@@ -45,7 +45,7 @@ static FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__Seekable
 static FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
 static FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
 static FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data);
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
 static void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
 static void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 
@@ -56,7 +56,7 @@ static void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__St
  ***********************************************************************/
 
 typedef struct FLAC__FileDecoderPrivate {
-       FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+       FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
        void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
        void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
        void *client_data;
@@ -71,7 +71,7 @@ typedef struct FLAC__FileDecoderPrivate {
  *
  ***********************************************************************/
 
-const char *FLAC__FileDecoderStateString[] = {
+const char * const FLAC__FileDecoderStateString[] = {
        "FLAC__FILE_DECODER_OK",
        "FLAC__FILE_DECODER_END_OF_FILE",
        "FLAC__FILE_DECODER_ERROR_OPENING_FILE",
@@ -243,7 +243,7 @@ FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const cha
        return true;
 }
 
-FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data))
+FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data))
 {
        FLAC__ASSERT(decoder != 0);
        FLAC__ASSERT(decoder->private_ != 0);
@@ -603,7 +603,7 @@ FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *clien
        return feof(file_decoder->private_->file);
 }
 
-FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
        FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
        (void)decoder;
index 5e5008d..f8eae47 100644 (file)
@@ -68,7 +68,7 @@ const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits
 
 const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
 
-const char *FLAC__EntropyCodingMethodTypeString[] = {
+const char * const FLAC__EntropyCodingMethodTypeString[] = {
        "PARTITIONED_RICE"
 };
 
@@ -84,26 +84,26 @@ const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
 const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
 const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
 
-const char *FLAC__SubframeTypeString[] = {
+const char * const FLAC__SubframeTypeString[] = {
        "CONSTANT",
        "VERBATIM",
        "FIXED",
        "LPC"
 };
 
-const char *FLAC__ChannelAssignmentString[] = {
+const char * const FLAC__ChannelAssignmentString[] = {
        "INDEPENDENT",
        "LEFT_SIDE",
        "RIGHT_SIDE",
        "MID_SIDE"
 };
 
-const char *FLAC__FrameNumberTypeString[] = {
+const char * const FLAC__FrameNumberTypeString[] = {
        "FRAME_NUMBER_TYPE_FRAME_NUMBER",
        "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
 };
 
-const char *FLAC__MetaDataTypeString[] = {
+const char * const FLAC__MetaDataTypeString[] = {
        "STREAMINFO",
        "PADDING",
        "APPLICATION",
index 96cb00f..5215c9a 100644 (file)
@@ -43,6 +43,6 @@ void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
 void MD5Final(md5byte digest[16], struct MD5Context *context);
 void MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]);
 
-FLAC__bool FLAC__MD5Accumulate(struct MD5Context *ctx, const FLAC__int32 *signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
+FLAC__bool FLAC__MD5Accumulate(struct MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
 
 #endif /* !MD5_H */
index b67efba..cfbe862 100644 (file)
@@ -221,7 +221,7 @@ MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
  * Convert the incoming audio signal to a byte stream and MD5Update it.
  */
 FLAC__bool
-FLAC__MD5Accumulate(struct MD5Context *ctx, const FLAC__int32 *signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+FLAC__MD5Accumulate(struct MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
 {
        unsigned channel, sample, a_byte;
        FLAC__int32 a_word;
index 875b000..b6f177f 100644 (file)
@@ -111,37 +111,54 @@ static FLAC__MetaData_ChainStatus get_equivalent_status_(FLAC__MetaData_SimpleIt
  *
  ***************************************************************************/
 
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
 static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
 static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 
+typedef struct {
+       FLAC__bool got_error;
+       FLAC__bool got_streaminfo;
+       FLAC__StreamMetaData_StreamInfo *streaminfo;
+} level0_client_data;
+
 FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetaData_StreamInfo *streaminfo)
 {
+       level0_client_data cd;
        FLAC__FileDecoder *decoder = FLAC__file_decoder_new();
 
        if(0 == decoder)
                return false;
 
+       cd.got_error = false;
+       cd.got_streaminfo = false;
+       cd.streaminfo = streaminfo;
+
        FLAC__file_decoder_set_md5_checking(decoder, false);
        FLAC__file_decoder_set_filename(decoder, filename);
        FLAC__file_decoder_set_write_callback(decoder, write_callback_);
        FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
        FLAC__file_decoder_set_error_callback(decoder, error_callback_);
-       FLAC__file_decoder_set_client_data(decoder, &streaminfo);
+       FLAC__file_decoder_set_client_data(decoder, &cd);
 
-       if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK)
+       if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) {
+               FLAC__file_decoder_finish(decoder);
+               FLAC__file_decoder_delete(decoder);
                return false;
+       }
 
-       if(!FLAC__file_decoder_process_metadata(decoder))
+       if(!FLAC__file_decoder_process_metadata(decoder) || cd.got_error) {
+               FLAC__file_decoder_finish(decoder);
+               FLAC__file_decoder_delete(decoder);
                return false;
+       }
 
        FLAC__file_decoder_finish(decoder);
        FLAC__file_decoder_delete(decoder);
 
-       return 0 != streaminfo; /* the metadata_callback_() will set streaminfo to 0 on an error */
+       return !cd.got_error && cd.got_streaminfo;
 }
 
-FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
        (void)decoder, (void)frame, (void)buffer, (void)client_data;
 
@@ -150,20 +167,22 @@ FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder,
 
 void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
 {
-       FLAC__StreamMetaData_StreamInfo **streaminfo = (FLAC__StreamMetaData_StreamInfo **)client_data;
+       level0_client_data *cd = (level0_client_data *)client_data;
        (void)decoder;
 
-       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && 0 != *streaminfo)
-               **streaminfo = metadata->data.stream_info;
+       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && 0 != cd->streaminfo) {
+               *(cd->streaminfo) = metadata->data.stream_info;
+               cd->got_streaminfo = true;
+       }
 }
 
 void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
-       FLAC__StreamMetaData_StreamInfo **streaminfo = (FLAC__StreamMetaData_StreamInfo **)client_data;
+       level0_client_data *cd = (level0_client_data *)client_data;
        (void)decoder;
 
        if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
-               *streaminfo = 0;
+               cd->got_error = true;
 }
 
 
@@ -193,7 +212,7 @@ struct FLAC__MetaData_SimpleIterator {
        unsigned length;
 };
 
-const char *FLAC__MetaData_SimpleIteratorStatusString[] = {
+const char * const FLAC__MetaData_SimpleIteratorStatusString[] = {
        "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
        "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
        "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
@@ -694,7 +713,7 @@ struct FLAC__MetaData_Iterator {
        FLAC__MetaData_Node *current;
 };
 
-const char *FLAC__MetaData_ChainStatusString[] = {
+const char * const FLAC__MetaData_ChainStatusString[] = {
        "FLAC__METADATA_CHAIN_STATUS_OK",
        "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
        "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
index aa379fa..21f81c4 100644 (file)
@@ -340,6 +340,124 @@ void FLAC__metadata_object_delete(FLAC__StreamMetaData *object)
        free(object);
 }
 
+static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetaData_StreamInfo *block1, const FLAC__StreamMetaData_StreamInfo *block2)
+{
+       if(block1->min_blocksize != block2->min_blocksize)
+               return false;
+       if(block1->max_blocksize != block2->max_blocksize)
+               return false;
+       if(block1->min_framesize != block2->min_framesize)
+               return false;
+       if(block1->max_framesize != block2->max_framesize)
+               return false;
+       if(block1->sample_rate != block2->sample_rate)
+               return false;
+       if(block1->channels != block2->channels)
+               return false;
+       if(block1->bits_per_sample != block2->bits_per_sample)
+               return false;
+       if(block1->total_samples != block2->total_samples)
+               return false;
+       if(0 != memcmp(block1->md5sum, block2->md5sum, 16))
+               return false;
+       return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetaData_Application *block1, const FLAC__StreamMetaData_Application *block2, unsigned block_length)
+{
+       FLAC__ASSERT(0 != block1);
+       FLAC__ASSERT(0 != block2);
+       FLAC__ASSERT(block_length >= sizeof(block1->id));
+
+       if(0 != memcmp(block1->id, block2->id, sizeof(block1->id)))
+               return false;
+       if(0 != block1->data && 0 != block2->data)
+               return 0 == memcmp(block1->data, block2->data, block_length - sizeof(block1->id));
+       else
+               return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetaData_SeekTable *block1, const FLAC__StreamMetaData_SeekTable *block2)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != block1);
+       FLAC__ASSERT(0 != block2);
+
+       if(block1->num_points != block2->num_points)
+               return false;
+
+       if(0 != block1->points && 0 != block2->points) {
+               for(i = 0; i < block1->num_points; i++) {
+                       if(block1->points[i].sample_number != block2->points[i].sample_number)
+                               return false;
+                       if(block1->points[i].stream_offset != block2->points[i].stream_offset)
+                               return false;
+                       if(block1->points[i].frame_samples != block2->points[i].frame_samples)
+                               return false;
+               }
+               return true;
+       }
+       else
+               return block1->points == block2->points;
+}
+
+static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetaData_VorbisComment *block1, const FLAC__StreamMetaData_VorbisComment *block2)
+{
+       unsigned i;
+
+       if(block1->vendor_string.length != block2->vendor_string.length)
+               return false;
+
+       if(0 != block1->vendor_string.entry && 0 != block2->vendor_string.entry) {
+               if(0 != memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length))
+                       return false;
+       }
+       else if(block1->vendor_string.entry != block2->vendor_string.entry)
+               return false;
+
+       if(block1->num_comments != block2->num_comments)
+               return false;
+
+       for(i = 0; i < block1->num_comments; i++) {
+               if(0 != block1->comments[i].entry && 0 != block2->comments[i].entry) {
+                       if(0 != memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length))
+                               return false;
+               }
+               else if(block1->comments[i].entry != block2->comments[i].entry)
+                       return false;
+       }
+       return true;
+}
+
+FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetaData *block1, const FLAC__StreamMetaData *block2)
+{
+       if(block1->type != block2->type) {
+               return false;
+    }
+       if(block1->is_last != block2->is_last) {
+               return false;
+    }
+       if(block1->length != block2->length) {
+               return false;
+    }
+       switch(block1->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+                       return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
+               case FLAC__METADATA_TYPE_PADDING:
+                       return true; /* we don't compare the padding guts */
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+               default:
+                       FLAC__ASSERT(0);
+                       return false;
+       }
+}
+
 /*@@@@move
 sets the application data to 'data'.  if 'copy' is true, makes, copy, else takes ownership of pointer.  returns false if copy==true and malloc fails.
     FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
index 2812240..9104e45 100644 (file)
@@ -33,7 +33,7 @@
 
 static void seekable_stream_decoder_set_defaults_(FLAC__SeekableStreamDecoder *decoder);
 static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
 static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
 static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 static FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
@@ -50,7 +50,7 @@ typedef struct FLAC__SeekableStreamDecoderPrivate {
        FLAC__SeekableStreamDecoderTellStatus (*tell_callback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
        FLAC__SeekableStreamDecoderLengthStatus (*length_callback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
        FLAC__bool (*eof_callback)(const FLAC__SeekableStreamDecoder *decoder, void *client_data);
-       FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+       FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
        void (*metadata_callback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
        void (*error_callback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
        void *client_data;
@@ -71,7 +71,7 @@ typedef struct FLAC__SeekableStreamDecoderPrivate {
  *
  ***********************************************************************/
 
-const char *FLAC__SeekableStreamDecoderStateString[] = {
+const char * const FLAC__SeekableStreamDecoderStateString[] = {
        "FLAC__SEEKABLE_STREAM_DECODER_OK",
        "FLAC__SEEKABLE_STREAM_DECODER_SEEKING",
        "FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM",
@@ -84,22 +84,22 @@ const char *FLAC__SeekableStreamDecoderStateString[] = {
     "FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED"
 };
 
-const char *FLAC__SeekableStreamDecoderReadStatusString[] = {
+const char * const FLAC__SeekableStreamDecoderReadStatusString[] = {
        "FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK",
        "FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR"
 };
 
-const char *FLAC__SeekableStreamDecoderSeekStatusString[] = {
+const char * const FLAC__SeekableStreamDecoderSeekStatusString[] = {
        "FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK",
        "FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR"
 };
 
-const char *FLAC__SeekableStreamDecoderTellStatusString[] = {
+const char * const FLAC__SeekableStreamDecoderTellStatusString[] = {
        "FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK",
        "FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR"
 };
 
-const char *FLAC__SeekableStreamDecoderLengthStatusString[] = {
+const char * const FLAC__SeekableStreamDecoderLengthStatusString[] = {
        "FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK",
        "FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR"
 };
@@ -302,7 +302,7 @@ FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDe
        return true;
 }
 
-FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data))
+FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data))
 {
        FLAC__ASSERT(decoder != 0);
        FLAC__ASSERT(decoder->private_ != 0);
@@ -670,7 +670,7 @@ FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder,
                return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
 }
 
-FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
        FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data;
        (void)decoder;
index fe8fa15..924c251 100644 (file)
@@ -68,7 +68,7 @@ static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *cli
 
 typedef struct FLAC__StreamDecoderPrivate {
        FLAC__StreamDecoderReadStatus (*read_callback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
-       FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+       FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
        void (*metadata_callback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
        void (*error_callback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
        void (*local_lpc_restore_signal)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
@@ -99,7 +99,7 @@ typedef struct FLAC__StreamDecoderPrivate {
  *
  ***********************************************************************/
 
-const char *FLAC__StreamDecoderStateString[] = {
+const char * const FLAC__StreamDecoderStateString[] = {
        "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
        "FLAC__STREAM_DECODER_READ_METADATA",
        "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
@@ -113,18 +113,18 @@ const char *FLAC__StreamDecoderStateString[] = {
        "FLAC__STREAM_DECODER_UNINITIALIZED"
 };
 
-const char *FLAC__StreamDecoderReadStatusString[] = {
+const char * const FLAC__StreamDecoderReadStatusString[] = {
        "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
        "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
        "FLAC__STREAM_DECODER_READ_STATUS_ABORT"
 };
 
-const char *FLAC__StreamDecoderWriteStatusString[] = {
+const char * const FLAC__StreamDecoderWriteStatusString[] = {
        "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
        "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
 };
 
-const char *FLAC__StreamDecoderErrorStatusString[] = {
+const char * const FLAC__StreamDecoderErrorStatusString[] = {
        "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
        "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
        "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH"
@@ -302,7 +302,7 @@ FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder,
        return true;
 }
 
-FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data))
+FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data))
 {
        FLAC__ASSERT(decoder != 0);
        FLAC__ASSERT(decoder->private_ != 0);
@@ -1247,8 +1247,7 @@ FLAC__bool stream_decoder_read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *
        decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
 
        /* write it */
-       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 3 here: */
-       if(decoder->private_->write_callback(decoder, &decoder->private_->frame, decoder->private_->output, decoder->private_->client_data) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
+       if(decoder->private_->write_callback(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output, decoder->private_->client_data) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
                return false;
 
        decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
index 55210cb..4c20b6c 100644 (file)
@@ -142,7 +142,7 @@ typedef struct FLAC__StreamEncoderPrivate {
  *
  ***********************************************************************/
 
-const char *FLAC__StreamEncoderStateString[] = {
+const char * const FLAC__StreamEncoderStateString[] = {
        "FLAC__STREAM_ENCODER_OK",
        "FLAC__STREAM_ENCODER_INVALID_CALLBACK",
        "FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS",
@@ -164,7 +164,7 @@ const char *FLAC__StreamEncoderStateString[] = {
        "FLAC__STREAM_ENCODER_UNINITIALIZED"
 };
 
-const char *FLAC__StreamEncoderWriteStatusString[] = {
+const char * const FLAC__StreamEncoderWriteStatusString[] = {
        "FLAC__STREAM_ENCODER_WRITE_OK",
        "FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR"
 };
@@ -473,7 +473,7 @@ FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder)
 
        FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame));
        {
-               FLAC__byte *buffer;
+               const FLAC__byte *buffer;
                unsigned bytes;
 
                FLAC__bitbuffer_get_buffer(encoder->private_->frame, &buffer, &bytes);
@@ -799,7 +799,7 @@ unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamE
        return encoder->protected_->rice_parameter_search_dist;
 }
 
-FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 *buf[], unsigned samples)
+FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
 {
        unsigned i, j, channel;
        FLAC__int32 x, mid, side;
@@ -812,15 +812,15 @@ FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC
        if(encoder->protected_->do_mid_side_stereo && channels == 2) {
                do {
                        for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
-                               x = mid = side = buf[0][j];
+                               x = mid = side = buffer[0][j];
                                encoder->private_->integer_signal[0][i] = x;
                                encoder->private_->real_signal[0][i] = (FLAC__real)x;
-                               x = buf[1][j];
+                               x = buffer[1][j];
                                encoder->private_->integer_signal[1][i] = x;
                                encoder->private_->real_signal[1][i] = (FLAC__real)x;
                                mid += x;
                                side -= x;
-                               mid >>= 1; /* NOTE: not the same as 'mid = (buf[0][j] + buf[1][j]) / 2' ! */
+                               mid >>= 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
                                encoder->private_->integer_signal_mid_side[1][i] = side;
                                encoder->private_->integer_signal_mid_side[0][i] = mid;
                                encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side;
@@ -837,7 +837,7 @@ FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC
                do {
                        for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
                                for(channel = 0; channel < channels; channel++) {
-                                       x = buf[channel][j];
+                                       x = buffer[channel][j];
                                        encoder->private_->integer_signal[channel][i] = x;
                                        encoder->private_->real_signal[channel][i] = (FLAC__real)x;
                                }
@@ -854,7 +854,7 @@ FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC
 }
 
 /* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */
-FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buf[], unsigned samples)
+FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
 {
        unsigned i, j, k, channel;
        FLAC__int32 x, mid, side;
@@ -867,10 +867,10 @@ FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder
        if(encoder->protected_->do_mid_side_stereo && channels == 2) {
                do {
                        for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
-                               x = mid = side = buf[k++];
+                               x = mid = side = buffer[k++];
                                encoder->private_->integer_signal[0][i] = x;
                                encoder->private_->real_signal[0][i] = (FLAC__real)x;
-                               x = buf[k++];
+                               x = buffer[k++];
                                encoder->private_->integer_signal[1][i] = x;
                                encoder->private_->real_signal[1][i] = (FLAC__real)x;
                                mid += x;
@@ -892,7 +892,7 @@ FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder
                do {
                        for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
                                for(channel = 0; channel < channels; channel++) {
-                                       x = buf[k++];
+                                       x = buffer[k++];
                                        encoder->private_->integer_signal[channel][i] = x;
                                        encoder->private_->real_signal[channel][i] = (FLAC__real)x;
                                }
@@ -977,8 +977,7 @@ FLAC__bool stream_encoder_process_frame_(FLAC__StreamEncoder *encoder, FLAC__boo
        /*
         * Accumulate raw signal to the MD5 signature
         */
-       /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-       if(!FLAC__MD5Accumulate(&encoder->private_->md5context, encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) {
+       if(!FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) {
                encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
                return false;
        }
index 9417d1d..a87fe82 100644 (file)
@@ -52,24 +52,26 @@ typedef struct {
        unsigned channels;
        unsigned sample_rate;
        unsigned length_in_ms;
-} stream_info_struct;
-
-static FLAC__bool stream_init(const char *infilename);
-static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
-static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
-static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+} file_info_struct;
+
+static FLAC__bool safe_decoder_init_(const char *infilename, FLAC__FileDecoder *decoder);
+static void safe_decoder_finish_(FLAC__FileDecoder *decoder);
+static void safe_decoder_delete_(FLAC__FileDecoder *decoder);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 static FLAC__bool get_id3v1_tag_(const char *filename, id3v1_struct *tag);
 
-In_Module mod; /* the output module (declared near the bottom of this file) */
-char lastfn[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
-int decode_pos_ms; /* current decoding position, in milliseconds */
-int paused; /* are we paused? */
-int seek_needed; /* if != -1, it is the point that the decode thread should seek to, in ms. */
-FLAC__int16 reservoir[FLAC__MAX_BLOCK_SIZE * 2 * 2]; /* *2 for max channels, another *2 for overflow */
-char sample_buffer[576 * 2 * (16/8) * 2]; /* 2 for max channels, (16/8) for max bytes per sample, and 2 for who knows what */
-unsigned samples_in_reservoir;
-static stream_info_struct stream_info;
-static FLAC__FileDecoder *decoder;
+In_Module mod_; /* the output module (declared near the bottom of this file) */
+char lastfn_[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
+int decode_pos_ms_; /* current decoding position, in milliseconds */
+int paused_; /* are we paused? */
+int seek_needed_; /* if != -1, it is the point that the decode thread should seek to, in ms. */
+FLAC__int16 reservoir_[FLAC__MAX_BLOCK_SIZE * 2 * 2]; /* *2 for max channels, another *2 for overflow */
+char sample_buffer_[576 * 2 * (16/8) * 2]; /* 2 for max channels, (16/8) for max bytes per sample, and 2 for who knows what */
+unsigned samples_in_reservoir_;
+static file_info_struct file_info_;
+static FLAC__FileDecoder *decoder_;
 
 int killDecodeThread = 0;                                      /* the kill switch for the decode thread */
 HANDLE thread_handle = INVALID_HANDLE_VALUE;   /* the handle to the decode thread */
@@ -88,15 +90,14 @@ void about(HWND hwndParent)
 
 void init()
 {
-       decoder = FLAC__file_decoder_new();
+       decoder_ = FLAC__file_decoder_new();
+       strcpy(lastfn_, "");
 }
 
 void quit()
 {
-       if(decoder) {
-               FLAC__file_decoder_delete(decoder);
-               decoder = 0;
-       }
+       safe_decoder_delete_(decoder_);
+       decoder_ = 0;
 }
 
 int isourfile(char *fn) { return 0; }
@@ -108,7 +109,7 @@ int play(char *fn)
        int thread_id;
        HANDLE input_file = INVALID_HANDLE_VALUE;
 
-       if(0 == decoder) {
+       if(0 == decoder_) {
                return 1;
        }
 
@@ -118,30 +119,30 @@ int play(char *fn)
        }
        CloseHandle(input_file);
 
-       if(!stream_init(fn)) {
+       if(!safe_decoder_init_(fn, decoder_)) {
                return 1;
        }
 
-       strcpy(lastfn, fn);
-       paused = 0;
-       decode_pos_ms = 0;
-       seek_needed = -1;
-       samples_in_reservoir = 0;
+       strcpy(lastfn_, fn);
+       paused_ = 0;
+       decode_pos_ms_ = 0;
+       seek_needed_ = -1;
+       samples_in_reservoir_ = 0;
 
-       maxlatency = mod.outMod->Open(stream_info.sample_rate, stream_info.channels, stream_info.bits_per_sample, -1, -1);
+       maxlatency = mod_.outMod->Open(file_info_.sample_rate, file_info_.channels, file_info_.bits_per_sample, -1, -1);
        if (maxlatency < 0) { /* error opening device */
                return 1;
        }
 
        /* dividing by 1000 for the first parameter of setinfo makes it */
        /* display 'H'... for hundred.. i.e. 14H Kbps. */
-       mod.SetInfo((stream_info.sample_rate*stream_info.bits_per_sample*stream_info.channels)/1000, stream_info.sample_rate/1000, stream_info.channels, 1);
+       mod_.SetInfo((file_info_.sample_rate*file_info_.bits_per_sample*file_info_.channels)/1000, file_info_.sample_rate/1000, file_info_.channels, 1);
 
        /* initialize vis stuff */
-       mod.SAVSAInit(maxlatency, stream_info.sample_rate);
-       mod.VSASetInfo(stream_info.sample_rate, stream_info.channels);
+       mod_.SAVSAInit(maxlatency, file_info_.sample_rate);
+       mod_.VSASetInfo(file_info_.sample_rate, file_info_.channels);
 
-       mod.outMod->SetVolume(-666); /* set the output plug-ins default volume */
+       mod_.outMod->SetVolume(-666); /* set the output plug-ins default volume */
 
        killDecodeThread = 0;
        thread_handle = (HANDLE) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, (void *) &killDecodeThread, 0, &thread_id);
@@ -151,18 +152,18 @@ int play(char *fn)
 
 void pause()
 {
-       paused = 1;
-       mod.outMod->Pause(1);
+       paused_ = 1;
+       mod_.outMod->Pause(1);
 }
 
 void unpause()
 {
-       paused = 0;
-       mod.outMod->Pause(0);
+       paused_ = 0;
+       mod_.outMod->Pause(0);
 }
 int ispaused()
 {
-       return paused;
+       return paused_;
 }
 
 void stop()
@@ -170,37 +171,36 @@ void stop()
        if (thread_handle != INVALID_HANDLE_VALUE) {
                killDecodeThread = 1;
                if (WaitForSingleObject(thread_handle, INFINITE) == WAIT_TIMEOUT) {
-                       MessageBox(mod.hMainWindow, "error asking thread to die!\n", "error killing decode thread", 0);
+                       MessageBox(mod_.hMainWindow, "error asking thread to die!\n", "error killing decode thread", 0);
                        TerminateThread(thread_handle, 0);
                }
                CloseHandle(thread_handle);
                thread_handle = INVALID_HANDLE_VALUE;
        }
-       if(decoder)
-               FLAC__file_decoder_finish(decoder);
+       safe_decoder_finish_(decoder_);
 
-       mod.outMod->Close();
+       mod_.outMod->Close();
 
-       mod.SAVSADeInit();
+       mod_.SAVSADeInit();
 }
 
 int getlength()
 {
-       return (int)stream_info.length_in_ms;
+       return (int)file_info_.length_in_ms;
 }
 
 int getoutputtime()
 {
-       return decode_pos_ms+(mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
+       return decode_pos_ms_ + (mod_.outMod->GetOutputTime() - mod_.outMod->GetWrittenTime());
 }
 
 void setoutputtime(int time_in_ms)
 {
-       seek_needed = time_in_ms;
+       seek_needed_ = time_in_ms;
 }
 
-void setvolume(int volume) { mod.outMod->SetVolume(volume); }
-void setpan(int pan) { mod.outMod->SetPan(pan); }
+void setvolume(int volume) { mod_.outMod->SetVolume(volume); }
+void setpan(int pan) { mod_.outMod->SetPan(pan); }
 
 int infoDlg(char *fn, HWND hwnd)
 {
@@ -211,41 +211,33 @@ int infoDlg(char *fn, HWND hwnd)
 void getfileinfo(char *filename, char *title, int *length_in_ms)
 {
        id3v1_struct tag;
+       FLAC__StreamMetaData_StreamInfo streaminfo;
 
-       if (!filename || !*filename) { /* currently playing file */
+       if(0 == filename) {
+               filename = lastfn_;
                if (length_in_ms) {
                        *length_in_ms = getlength();
                        length_in_ms = 0; /* force skip in following code */
                }
-               if (title && lastfn && lastfn[0]) {
-                       filename = lastfn;
-               }
        }
 
-       if (length_in_ms) {
-               FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_new();
-               stream_info_struct tmp_stream_info;
-               tmp_stream_info.abort_flag = false;
-               FLAC__file_decoder_set_md5_checking(tmp_decoder, false);
-               FLAC__file_decoder_set_filename(tmp_decoder, filename);
-               FLAC__file_decoder_set_write_callback(tmp_decoder, write_callback);
-               FLAC__file_decoder_set_metadata_callback(tmp_decoder, metadata_callback);
-               FLAC__file_decoder_set_error_callback(tmp_decoder, error_callback);
-               FLAC__file_decoder_set_client_data(tmp_decoder, &tmp_stream_info);
-               if(FLAC__file_decoder_init(tmp_decoder) != FLAC__FILE_DECODER_OK)
-                       return;
-               if(!FLAC__file_decoder_process_metadata(tmp_decoder))
-                       return;
-
-               *length_in_ms = (int)tmp_stream_info.length_in_ms;
-
-               FLAC__file_decoder_finish(tmp_decoder);
-               FLAC__file_decoder_delete(tmp_decoder);
+       if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
+               MessageBox(mod_.hMainWindow, filename, "ERROR: invalid/missing FLAC metadata", 0);
+               if(title) {
+                       static const char *errtitle = "Invalid FLAC File: ");
+                       sprintf(title, "%s\"%s\"", errtitle, filename);
+               }
+               if(length_in_msec)
+                       *length_in_msec = -1;
+               return;
        }
-       if (title) {
+
+       if(title) {
                (void)get_id3v1_tag_(filename, &tag);
                strcpy(title, tag.description);
        }
+       if(length_in_msec)
+               *length_in_msec = streaminfo.total_samples * 10 / (streaminfo.sample_rate / 100);
 }
 
 void eq_set(int on, char data[10], int preamp)
@@ -257,60 +249,60 @@ DWORD WINAPI __stdcall DecodeThread(void *b)
        int done = 0;
 
        while (! *((int *)b) ) {
-               unsigned channels = stream_info.channels;
-               unsigned bits_per_sample = stream_info.bits_per_sample;
+               unsigned channels = file_info_.channels;
+               unsigned bits_per_sample = file_info_.bits_per_sample;
                unsigned bytes_per_sample = (bits_per_sample+7)/8;
-               unsigned sample_rate = stream_info.sample_rate;
-               if (seek_needed != -1) {
-                       const double distance = (double)seek_needed / (double)getlength();
-                       unsigned target_sample = (unsigned)(distance * (double)stream_info.total_samples);
-                       if(FLAC__file_decoder_seek_absolute(decoder, (FLAC__uint64)target_sample)) {
-                               decode_pos_ms = (int)(distance * (double)getlength());
-                               seek_needed = -1;
+               unsigned sample_rate = file_info_.sample_rate;
+               if (seek_needed_ != -1) {
+                       const double distance = (double)seek_needed_ / (double)getlength();
+                       unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
+                       if(FLAC__file_decoder_seek_absolute(decoder_, (FLAC__uint64)target_sample)) {
+                               decode_pos_ms_ = (int)(distance * (double)getlength());
+                               seek_needed_ = -1;
                                done = 0;
-                               mod.outMod->Flush(decode_pos_ms);
+                               mod_.outMod->Flush(decode_pos_ms_);
                        }
                }
                if (done) {
-                       if (!mod.outMod->IsPlaying()) {
-                               PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
+                       if (!mod_.outMod->IsPlaying()) {
+                               PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
                                return 0;
                        }
                        Sleep(10);
                }
-               else if (mod.outMod->CanWrite() >= ((int)(576*channels*bytes_per_sample) << (mod.dsp_isactive()?1:0))) {
-                       while(samples_in_reservoir < 576) {
-                               if(FLAC__file_decoder_get_state(decoder) == FLAC__FILE_DECODER_END_OF_FILE) {
+               else if (mod_.outMod->CanWrite() >= ((int)(576*channels*bytes_per_sample) << (mod_.dsp_isactive()?1:0))) {
+                       while(samples_in_reservoir_ < 576) {
+                               if(FLAC__file_decoder_get_state(decoder_) == FLAC__FILE_DECODER_END_OF_FILE) {
                                        done = 1;
                                        break;
                                }
-                               else if(!FLAC__file_decoder_process_one_frame(decoder))
+                               else if(!FLAC__file_decoder_process_one_frame(decoder_))
                                        break;
                        }
 
-                       if (samples_in_reservoir == 0) {
+                       if (samples_in_reservoir_ == 0) {
                                done = 1;
                        }
                        else {
-                               unsigned i, n = min(samples_in_reservoir, 576), delta;
+                               unsigned i, n = min(samples_in_reservoir_, 576), delta;
                                int bytes;
-                               signed short *ssbuffer = (signed short *)sample_buffer;
+                               signed short *ssbuffer = (signed short *)sample_buffer_;
 
                                for(i = 0; i < n*channels; i++)
-                                       ssbuffer[i] = reservoir[i];
+                                       ssbuffer[i] = reservoir_[i];
                                delta = i;
-                               for( ; i < samples_in_reservoir*channels; i++)
-                                       reservoir[i-delta] = reservoir[i];
-                               samples_in_reservoir -= n;
-
-                               mod.SAAddPCMData((char *)sample_buffer, channels, bits_per_sample, decode_pos_ms);
-                               mod.VSAAddPCMData((char *)sample_buffer, channels, bits_per_sample, decode_pos_ms);
-                               decode_pos_ms += (n*1000 + sample_rate/2)/sample_rate;
-                               if (mod.dsp_isactive())
-                                       bytes = mod.dsp_dosamples((short *)sample_buffer, n, bits_per_sample, channels, sample_rate) * (channels*bytes_per_sample);
+                               for( ; i < samples_in_reservoir_ * channels; i++)
+                                       reservoir_[i-delta] = reservoir_[i];
+                               samples_in_reservoir_ -= n;
+
+                               mod_.SAAddPCMData((char *)sample_buffer_, channels, bits_per_sample, decode_pos_ms_);
+                               mod_.VSAAddPCMData((char *)sample_buffer_, channels, bits_per_sample, decode_pos_ms_);
+                               decode_pos_ms_ += (n*1000 + sample_rate/2)/sample_rate;
+                               if (mod_.dsp_isactive())
+                                       bytes = mod_.dsp_dosamples((short *)sample_buffer_, n, bits_per_sample, channels, sample_rate) * (channels*bytes_per_sample);
                                else
                                        bytes = n * channels * bytes_per_sample;
-                               mod.outMod->Write(sample_buffer, bytes);
+                               mod_.outMod->Write(sample_buffer_, bytes);
                        }
                }
                else Sleep(20);
@@ -320,7 +312,7 @@ DWORD WINAPI __stdcall DecodeThread(void *b)
 
 
 
-In_Module mod =
+In_Module mod_ =
 {
        IN_VER,
        "Reference FLAC Player v" FLAC__VERSION_STRING,
@@ -365,80 +357,102 @@ In_Module mod =
 
 __declspec( dllexport ) In_Module * winampGetInModule2()
 {
-       return &mod;
+       return &mod_;
 }
 
 
 /***********************************************************************
  * local routines
  **********************************************************************/
-FLAC__bool stream_init(const char *infilename)
+FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder)
 {
+       if(decoder == 0) {
+               MessageBox(mod_.hMainWindow, "Decoder instance is NULL", "ERROR initializing decoder", 0);
+               return false;
+       }
+
+       safe_decoder_finish_(decoder);
+
        FLAC__file_decoder_set_md5_checking(decoder, false);
-       FLAC__file_decoder_set_filename(decoder, infilename);
-       FLAC__file_decoder_set_write_callback(decoder, write_callback);
-       FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
-       FLAC__file_decoder_set_error_callback(decoder, error_callback);
-       FLAC__file_decoder_set_client_data(decoder, &stream_info);
+       FLAC__file_decoder_set_filename(decoder, filename);
+       FLAC__file_decoder_set_write_callback(decoder, write_callback_);
+       FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
+       FLAC__file_decoder_set_error_callback(decoder, error_callback_);
+       FLAC__file_decoder_set_client_data(decoder, &file_info_);
        if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
-               MessageBox(mod.hMainWindow, "ERROR initializing decoder, state = %d\n", "ERROR initializing decoder", 0);
+               MessageBox(mod_.hMainWindow, FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)], "ERROR initializing decoder", 0);
                return false;
        }
 
-       stream_info.abort_flag = false;
+       file_info_.abort_flag = false;
        if(!FLAC__file_decoder_process_metadata(decoder)) {
+               MessageBox(mod_.hMainWindow, FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)], "ERROR processing metadata", 0);
                return false;
        }
 
        return true;
 }
 
-FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+void safe_decoder_finish_(FLAC__FileDecoder *decoder)
+{
+       if(decoder && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
+               FLAC__file_decoder_finish(decoder);
+}
+
+void safe_decoder_delete_(FLAC__FileDecoder *decoder)
+{
+       if(decoder) {
+               safe_decoder_finish_(decoder);
+               FLAC__file_decoder_delete(decoder);
+       }
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
 {
-       stream_info_struct *stream_info = (stream_info_struct *)client_data;
-       const unsigned bps = stream_info->bits_per_sample, channels = stream_info->channels, wide_samples = frame->header.blocksize;
+       file_info_struct *file_info_ = (file_info_struct *)client_data;
+       const unsigned bps = file_info_->bits_per_sample, channels = file_info_->channels, wide_samples = frame->header.blocksize;
        unsigned wide_sample, sample, channel;
 
        (void)decoder;
 
-       if(stream_info->abort_flag)
+       if(file_info_->abort_flag)
                return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 
-       for(sample = samples_in_reservoir*channels, wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+       for(sample = samples_in_reservoir_ * channels, wide_sample = 0; wide_sample < wide_samples; wide_sample++)
                for(channel = 0; channel < channels; channel++, sample++)
-                       reservoir[sample] = (FLAC__int16)buffer[channel][wide_sample];
+                       reservoir_[sample] = (FLAC__int16)buffer[channel][wide_sample];
 
-       samples_in_reservoir += wide_samples;
+       samples_in_reservoir_ += wide_samples;
 
        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 }
 
-void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
 {
-       stream_info_struct *stream_info = (stream_info_struct *)client_data;
+       file_info_struct *file_info_ = (file_info_struct *)client_data;
        (void)decoder;
        if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
                FLAC__ASSERT(metadata->data.stream_info.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
-               stream_info->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xffffffff);
-               stream_info->bits_per_sample = metadata->data.stream_info.bits_per_sample;
-               stream_info->channels = metadata->data.stream_info.channels;
-               stream_info->sample_rate = metadata->data.stream_info.sample_rate;
-
-               if(stream_info->bits_per_sample != 16) {
-                       MessageBox(mod.hMainWindow, "ERROR: plugin can only handle 16-bit samples\n", "ERROR: plugin can only handle 16-bit samples", 0);
-                       stream_info->abort_flag = true;
+               file_info_->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xffffffff);
+               file_info_->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+               file_info_->channels = metadata->data.stream_info.channels;
+               file_info_->sample_rate = metadata->data.stream_info.sample_rate;
+
+               if(file_info_->bits_per_sample != 16) {
+                       MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 16-bit samples\n", "ERROR: plugin can only handle 16-bit samples", 0);
+                       file_info_->abort_flag = true;
                        return;
                }
-               stream_info->length_in_ms = stream_info->total_samples * 10 / (stream_info->sample_rate / 100);
+               file_info_->length_in_ms = file_info_->total_samples * 10 / (file_info_->sample_rate / 100);
        }
 }
 
-void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
-       stream_info_struct *stream_info = (stream_info_struct *)client_data;
+       file_info_struct *file_info_ = (file_info_struct *)client_data;
        (void)decoder;
        if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
-               stream_info->abort_flag = true;
+               file_info_->abort_flag = true;
 }
 
 FLAC__bool get_id3v1_tag_(const char *filename, id3v1_struct *tag)
index 45cc23c..1e1cdff 100644 (file)
@@ -69,7 +69,9 @@ static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
 
 static FLAC__bool get_id3v1_tag_(const char *filename, id3v1_struct *tag);
 static void *play_loop_(void *arg);
-static FLAC__bool decoder_init_(const char *filename);
+static FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder);
+static FLAC__bool safe_decoder_finish_(FLAC__FileDecoder *decoder);
+static FLAC__bool safe_decoder_delete_(FLAC__FileDecoder *decoder);
 static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
 static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
 static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
@@ -150,15 +152,17 @@ void FLAC_XMMS__play_file(char *filename)
                return;
        fclose(f);
 
-       if(!decoder_init_(filename))
+       if(decoder_ == 0)
+               return;
+
+       if(!safe_decoder_init_(filename, decoder_))
                return;
 
        file_info_.is_playing = true;
 
        if(flac_ip.output->open_audio(file_info_.sample_format, file_info_.sample_rate, file_info_.channels) == 0) {
                audio_error_ = true;
-               if(decoder_)
-                       FLAC__file_decoder_finish(decoder_);
+               safe_decoder_finish_(decoder_);
                return;
        }
 
@@ -179,8 +183,7 @@ void FLAC_XMMS__stop()
                        pthread_join(decode_thread_, NULL);
                }
                flac_ip.output->close_audio();
-               if(decoder_)
-                       FLAC__file_decoder_finish(decoder_);
+               safe_decoder_finish_(decoder_);
        }
 }
 
@@ -210,49 +213,37 @@ int FLAC_XMMS__get_time()
 
 void FLAC_XMMS__cleanup()
 {
-       if(decoder_) {
-               FLAC__file_decoder_delete(decoder_);
-               decoder_ = 0;
-       }
+       safe_decoder_delete(decoder_);
+       decoder_ = 0;
 }
 
 void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
 {
        id3v1_struct tag;
+       FLAC__StreamMetaData_StreamInfo streaminfo;
+
+       if(0 == filename)
+               filename = "";
+
+       if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
+               /* @@@ how to report the error? */
+               if(title) {
+                       static const char *errtitle = "Invalid FLAC File: ");
+                       *title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1);
+                       sprintf(*title, "%s\"%s\"", errtitle, filename);
+               }
+               if(length_in_msec)
+                       *length_in_msec = -1;
+               return;
+       }
 
        if(title) {
                (void)get_id3v1_tag_(filename, &tag);
                *title = g_malloc(strlen(tag.description)+1);
                strcpy(*title, tag.description);
        }
-       if(length_in_msec) {
-               FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_new();
-               file_info_struct tmp_file_info;
-               if(0 == tmp_decoder) {
-                       *length_in_msec = -1;
-                       return;
-               }
-               tmp_file_info.abort_flag = false;
-               FLAC__file_decoder_set_md5_checking(tmp_decoder, false);
-               FLAC__file_decoder_set_filename(tmp_decoder, filename);
-               FLAC__file_decoder_set_write_callback(tmp_decoder, write_callback_);
-               FLAC__file_decoder_set_metadata_callback(tmp_decoder, metadata_callback_);
-               FLAC__file_decoder_set_error_callback(tmp_decoder, error_callback_);
-               FLAC__file_decoder_set_client_data(tmp_decoder, &tmp_file_info);
-               if(FLAC__file_decoder_init(tmp_decoder) != FLAC__FILE_DECODER_OK) {
-                       *length_in_msec = -1;
-                       return;
-               }
-               if(!FLAC__file_decoder_process_metadata(tmp_decoder)) {
-                       *length_in_msec = -1;
-                       return;
-               }
-
-               *length_in_msec = (int)tmp_file_info.length_in_msec;
-
-               FLAC__file_decoder_finish(tmp_decoder);
-               FLAC__file_decoder_delete(tmp_decoder);
-       }
+       if(length_in_msec)
+               *length_in_msec = streaminfo.total_samples * 10 / (streaminfo.sample_rate / 100);
 }
 
 /***********************************************************************
@@ -357,8 +348,7 @@ void *play_loop_(void *arg)
                }
        }
 
-       if(decoder_)
-               FLAC__file_decoder_finish(decoder_);
+       safe_decoder_finish_(decoder_);
 
        /* are these two calls necessary? */
        flac_ip.output->buffer_free();
@@ -368,26 +358,42 @@ void *play_loop_(void *arg)
        return 0; /* to silence the compiler warning about not returning a value */
 }
 
-FLAC__bool decoder_init_(const char *filename)
+FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder)
 {
-       if(decoder_ == 0)
+       if(decoder == 0)
                return false;
 
-       FLAC__file_decoder_set_md5_checking(decoder_, false);
-       FLAC__file_decoder_set_filename(decoder_, filename);
-       FLAC__file_decoder_set_write_callback(decoder_, write_callback_);
-       FLAC__file_decoder_set_metadata_callback(decoder_, metadata_callback_);
-       FLAC__file_decoder_set_error_callback(decoder_, error_callback_);
-       FLAC__file_decoder_set_client_data(decoder_, &file_info_);
-       if(FLAC__file_decoder_init(decoder_) != FLAC__FILE_DECODER_OK)
+       safe_decoder_finish_(decoder);
+
+       FLAC__file_decoder_set_md5_checking(decoder, false);
+       FLAC__file_decoder_set_filename(decoder, filename);
+       FLAC__file_decoder_set_write_callback(decoder, write_callback_);
+       FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
+       FLAC__file_decoder_set_error_callback(decoder, error_callback_);
+       FLAC__file_decoder_set_client_data(decoder, &file_info_);
+       if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK)
                return false;
 
-       if(!FLAC__file_decoder_process_metadata(decoder_))
+       if(!FLAC__file_decoder_process_metadata(decoder))
                return false;
 
        return true;
 }
 
+void safe_decoder_finish_(FLAC__FileDecoder *decoder)
+{
+       if(decoder && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
+               FLAC__file_decoder_finish(decoder);
+}
+
+void safe_decoder_delete_(FLAC__FileDecoder *decoder)
+{
+       if(decoder) {
+               safe_decoder_finish_(decoder);
+               FLAC__file_decoder_delete(decoder);
+       }
+}
+
 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
 {
        file_info_struct *file_info = (file_info_struct *)client_data;
diff --git a/src/test_libFLAC++/Makefile.am b/src/test_libFLAC++/Makefile.am
new file mode 100644 (file)
index 0000000..6e3202e
--- /dev/null
@@ -0,0 +1,34 @@
+#  test_libFLAC++ - Unit tester for libFLAC++
+#  Copyright (C) 2002  Josh Coalson
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+CFLAGS = @CFLAGS@
+
+noinst_PROGRAMS = test_libFLAC++
+test_libFLAC___LDADD = $(top_builddir)/src/libFLAC++/libFLAC++.la $(top_builddir)/src/libFLAC/libFLAC.la -lm
+test_libFLAC___SOURCES = \
+       decoders.cc \
+       encoders.cc \
+       file_utils.c \
+       main.cc \
+       metadata.cc \
+       metadata_manip.cc \
+       metadata_object.cc \
+       bitbuffer.h \
+       decoders.h \
+       encoders.h \
+       file_utils.h \
+       metadata.h
diff --git a/src/test_libFLAC++/Makefile.lite b/src/test_libFLAC++/Makefile.lite
new file mode 100644 (file)
index 0000000..d985090
--- /dev/null
@@ -0,0 +1,38 @@
+#  test_libFLAC++ - Unit tester for libFLAC++
+#  Copyright (C) 2002  Josh Coalson
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+#
+# GNU makefile
+#
+
+PROGRAM_NAME = test_libFLAC++
+INCLUDES     = -I../../include
+LIBS         = -lFLAC++ -lFLAC -lm
+OBJS = \
+       decoders.o \
+       encoders.o \
+       file_utils.o \
+       main.o \
+       metadata.o \
+       metadata_manip.o \
+       metadata_object.o
+
+include ../../build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libFLAC++/Makefile.vc b/src/test_libFLAC++/Makefile.vc
new file mode 100644 (file)
index 0000000..5af32f8
--- /dev/null
@@ -0,0 +1,73 @@
+#  test_libFLAC++ - Unit tester for libFLAC++\r
+#  Copyright (C) 2002  Josh Coalson\r
+#\r
+#  This program is free software; you can redistribute it and/or\r
+#  modify it under the terms of the GNU General Public License\r
+#  as published by the Free Software Foundation; either version 2\r
+#  of the License, or (at your option) any later version.\r
+#\r
+#  This program is distributed in the hope that it will be useful,\r
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+#  GNU General Public License for more details.\r
+#\r
+#  You should have received a copy of the GNU General Public License\r
+#  along with this program; if not, write to the Free Software\r
+#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+\r
+!include <win32.mak>\r
+\r
+SUFFIXES = .cpp\r
+\r
+!IFDEF DEBUG\r
+.c.obj:\r
+       $(cc) $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -DVERSION=\"1.0.3\" -YX /Od /D "_DEBUG" $<\r
+!else\r
+.c.obj:\r
+       $(cc) /O2 $(crelease) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -DVERSION=\"1.0.3\" -YX -DNODEBUG $<\r
+!endif\r
+\r
+!IFDEF DEBUG\r
+.cc.obj:\r
+       $(cc) /D "_LIB" /GX $(cdebug) $(cflags) /I "..\..\include" -DSTRICT -YX /Od /D "_DEBUG" $<\r
+!else\r
+.cc.obj:\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG $<\r
+!endif\r
+\r
+C_FILES= \\r
+       file_utils.c\r
+\r
+CC_FILES= \\r
+       decoders.cc \\r
+       encoders.cc \\r
+       main.cc \\r
+       metadata.cc \\r
+       metadata_manip.cc \\r
+       metadata_object.cc\r
+\r
+OBJS= $(C_FILES:.c=.obj)\r
+OBJS= $(CC_FILES:.cc=.obj)\r
+\r
+# can't figure out how to get it to take .cc so we just hack it for now:\r
+decoders.obj: decoders.cc\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG /TP decoders.cc\r
+encoders.obj: encoders.cc\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG /TP encoders.cc\r
+main.obj: main.cc\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG /TP main.cc\r
+metadata.obj: metadata.cc\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG /TP metadata.cc\r
+metadata_manip.obj: metadata_manip.cc\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG /TP metadata_manip.cc\r
+metadata_object.obj: metadata_object.cc\r
+       $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I "..\..\include" -DSTRICT -YX -DNODEBUG /TP metadata_object.cc\r
+\r
+all: test_libFLAC++.exe\r
+\r
+test_libFLAC++.exe: $(OBJS)\r
+       link.exe /libpath:"..\..\obj\lib" -out:../../obj/bin/$*.exe $(OBJS) libFLAC++.lib libFLAC.lib\r
+\r
+clean:\r
+       -del *.obj *.pch\r
+       -del ..\..\obj\bin\test_libFLAC++.exe\r
diff --git a/src/test_libFLAC++/README b/src/test_libFLAC++/README
new file mode 100644 (file)
index 0000000..d2b766c
--- /dev/null
@@ -0,0 +1,4 @@
+NOTE: files file_utils.c and file_utils.h are copied from the
+../test_libFLAC directory.  It's too much pain to make a
+convenience library for these and CVS can't do soft links, so
+we put up with having two copies of these sources.
diff --git a/src/test_libFLAC++/decoders.cc b/src/test_libFLAC++/decoders.cc
new file mode 100644 (file)
index 0000000..d592bd2
--- /dev/null
@@ -0,0 +1,2005 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "decoders.h"
+extern "C" {
+#include "file_utils.h"
+}
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h" // for ::FLAC__metadata_object_is_equal()
+#include "FLAC++/decoder.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static ::FLAC__StreamMetaData streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_;
+static ::FLAC__StreamMetaData *expected_metadata_sequence_[6];
+static unsigned num_expected_;
+static const char *flacfilename_ = "metadata.flac";
+static unsigned flacfilesize_;
+
+static bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static void *malloc_or_die_(size_t size)
+{
+       void *x = malloc(size);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
+               exit(1);
+       }
+       return x;
+}
+
+static void init_metadata_blocks_()
+{
+       /*
+               most of the actual numbers and data in the blocks don't matter,
+               we just want to make sure the decoder parses them correctly
+
+               remember, the metadata interface gets tested after the decoders,
+               so we do all the metadata manipulation here without it.
+       */
+
+       /* min/max_framesize and md5sum don't get written at first, so we have to leave them 0 */
+    streaminfo_.is_last = false;
+    streaminfo_.type = ::FLAC__METADATA_TYPE_STREAMINFO;
+    streaminfo_.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+    streaminfo_.data.stream_info.min_blocksize = 576;
+    streaminfo_.data.stream_info.max_blocksize = 576;
+    streaminfo_.data.stream_info.min_framesize = 0;
+    streaminfo_.data.stream_info.max_framesize = 0;
+    streaminfo_.data.stream_info.sample_rate = 44100;
+    streaminfo_.data.stream_info.channels = 1;
+    streaminfo_.data.stream_info.bits_per_sample = 8;
+    streaminfo_.data.stream_info.total_samples = 0;
+       memset(streaminfo_.data.stream_info.md5sum, 0, 16);
+
+    padding_.is_last = false;
+    padding_.type = ::FLAC__METADATA_TYPE_PADDING;
+    padding_.length = 1234;
+
+    seektable_.is_last = false;
+    seektable_.type = ::FLAC__METADATA_TYPE_SEEKTABLE;
+       seektable_.data.seek_table.num_points = 2;
+    seektable_.length = seektable_.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+       seektable_.data.seek_table.points = (::FLAC__StreamMetaData_SeekPoint*)malloc_or_die_(seektable_.data.seek_table.num_points * sizeof(::FLAC__StreamMetaData_SeekPoint));
+       seektable_.data.seek_table.points[0].sample_number = 0;
+       seektable_.data.seek_table.points[0].stream_offset = 0;
+       seektable_.data.seek_table.points[0].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+       seektable_.data.seek_table.points[1].sample_number = ::FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+       seektable_.data.seek_table.points[1].stream_offset = 1000;
+       seektable_.data.seek_table.points[1].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+
+    application1_.is_last = false;
+    application1_.type = ::FLAC__METADATA_TYPE_APPLICATION;
+    application1_.length = 8;
+       memcpy(application1_.data.application.id, "\xfe\xdc\xba\x98", 4);
+       application1_.data.application.data = (FLAC__byte*)malloc_or_die_(4);
+       memcpy(application1_.data.application.data, "\xf0\xe1\xd2\xc3", 4);
+
+    application2_.is_last = false;
+    application2_.type = ::FLAC__METADATA_TYPE_APPLICATION;
+    application2_.length = 4;
+       memcpy(application2_.data.application.id, "\x76\x54\x32\x10", 4);
+       application2_.data.application.data = 0;
+
+    vorbiscomment_.is_last = true;
+    vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+    vorbiscomment_.length = (4 + 8) + 4 + (4 + 5) + (4 + 0);
+       vorbiscomment_.data.vorbis_comment.vendor_string.length = 8;
+       vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(8);
+       memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "flac 1.x", 8);
+       vorbiscomment_.data.vorbis_comment.num_comments = 2;
+       vorbiscomment_.data.vorbis_comment.comments = (::FLAC__StreamMetaData_VorbisComment_Entry*)malloc_or_die_(vorbiscomment_.data.vorbis_comment.num_comments * sizeof(::FLAC__StreamMetaData_VorbisComment_Entry));
+       vorbiscomment_.data.vorbis_comment.comments[0].length = 5;
+       vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
+       memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+       vorbiscomment_.data.vorbis_comment.comments[1].length = 0;
+       vorbiscomment_.data.vorbis_comment.comments[1].entry = 0;
+}
+
+static void free_metadata_blocks_()
+{
+       free(seektable_.data.seek_table.points);
+       free(application1_.data.application.data);
+       free(vorbiscomment_.data.vorbis_comment.vendor_string.entry);
+       free(vorbiscomment_.data.vorbis_comment.comments[0].entry);
+       free(vorbiscomment_.data.vorbis_comment.comments);
+}
+
+static bool generate_file_()
+{
+       printf("\n\ngenerating FLAC file for decoder tests...\n");
+
+       expected_metadata_sequence_[0] = &padding_;
+       expected_metadata_sequence_[1] = &seektable_;
+       expected_metadata_sequence_[2] = &application1_;
+       expected_metadata_sequence_[3] = &application2_;
+       expected_metadata_sequence_[4] = &vorbiscomment_;
+       num_expected_ = 5;
+
+       if(!file_utils__generate_flacfile(flacfilename_, &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+               return die_("creating the encoded file"); 
+
+       return true;
+}
+
+
+class DecoderCommon {
+public:
+       FILE *file_;
+       unsigned current_metadata_number_;
+       bool ignore_errors_;
+       bool error_occurred_;
+
+       DecoderCommon(): file_(0), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false) { }
+       ::FLAC__StreamDecoderReadStatus common_read_callback_(FLAC__byte buffer[], unsigned *bytes);
+       ::FLAC__StreamDecoderWriteStatus common_write_callback_(const ::FLAC__Frame *frame);
+       void common_metadata_callback_(const ::FLAC__StreamMetaData *metadata);
+       void common_error_callback_(::FLAC__StreamDecoderErrorStatus status);
+};
+
+::FLAC__StreamDecoderReadStatus DecoderCommon::common_read_callback_(FLAC__byte buffer[], unsigned *bytes)
+{
+       if(error_occurred_)
+               return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+       if(feof(file_))
+               return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+    else if(*bytes > 0) {
+        unsigned bytes_read = ::fread(buffer, 1, *bytes, file_);
+        if(bytes_read == 0) {
+            if(feof(file_))
+                return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+            else
+                return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+        }
+        else {
+            *bytes = bytes_read;
+            return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+        }
+    }
+    else
+        return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+::FLAC__StreamDecoderWriteStatus DecoderCommon::common_write_callback_(const ::FLAC__Frame *frame)
+{
+       if(error_occurred_)
+               return ::FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+    if(
+        (frame->header.number_type == ::FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+        (frame->header.number_type == ::FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+    ) {
+        printf("content... ");
+        fflush(stdout);
+    }
+
+       return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void DecoderCommon::common_metadata_callback_(const ::FLAC__StreamMetaData *metadata)
+{
+       if(error_occurred_)
+               return;
+
+       printf("%d... ", current_metadata_number_);
+       fflush(stdout);
+
+       if(current_metadata_number_ >= num_expected_) {
+               (void)die_("got more metadata blocks than expected");
+               error_occurred_ = true;
+       }
+       else {
+               if(!::FLAC__metadata_object_is_equal(expected_metadata_sequence_[current_metadata_number_], metadata)) {
+                       (void)die_("metadata block mismatch");
+                       error_occurred_ = true;
+               }
+       }
+       current_metadata_number_++;
+}
+
+void DecoderCommon::common_error_callback_(::FLAC__StreamDecoderErrorStatus status)
+{
+       if(!ignore_errors_) {
+               printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, ::FLAC__StreamDecoderErrorStatusString[status]);
+               error_occurred_ = true;
+       }
+}
+
+class StreamDecoder : public FLAC::Decoder::Stream, public DecoderCommon {
+public:
+       StreamDecoder(): FLAC::Decoder::Stream(), DecoderCommon() { }
+       ~StreamDecoder() { }
+
+       // from FLAC::Decoder::Stream
+       ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes);
+       ::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__StreamDecoderReadStatus StreamDecoder::read_callback(FLAC__byte buffer[], unsigned *bytes)
+{
+       return common_read_callback_(buffer, bytes);
+}
+
+::FLAC__StreamDecoderWriteStatus StreamDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       (void)buffer;
+
+       return common_write_callback_(frame);
+}
+
+void StreamDecoder::metadata_callback(const ::FLAC__StreamMetaData *metadata)
+{
+       return common_metadata_callback_(metadata);
+}
+
+void StreamDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+       return common_error_callback_(status);
+}
+
+bool StreamDecoder::die(const char *msg) const
+{
+       State state = get_state();
+
+       if(msg)
+               printf("FAILED, %s, state = %u (%s)\n", msg, (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+       else
+               printf("FAILED, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+
+       return false;
+}
+
+bool StreamDecoder::test_respond()
+{
+       printf("testing init()... ");
+       if(init() != ::FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+               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_whole_stream()... ");
+       if(!process_whole_stream()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       finish();
+       printf("OK\n");
+
+       return true;
+}
+
+static bool test_stream_decoder()
+{
+       StreamDecoder *decoder;
+
+       printf("\n+++ unit test: FLAC::Decoder::Stream\n\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("allocating decoder instance... ");
+       decoder = new StreamDecoder();
+       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() != ::FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       FLAC::Decoder::Stream::State state = decoder->get_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 FLAC file... ");
+       decoder->file_ = ::fopen(flacfilename_, "rb");
+       if(0 == decoder->file_) {
+               printf("ERROR\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing process_metadata()... ");
+       if(!decoder->process_metadata())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_one_frame()... ");
+       if(!decoder->process_one_frame())
+               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_one_frame()... ");
+       if(!decoder->process_one_frame())
+               return decoder->die("returned false");
+       printf("OK\n");
+       decoder->ignore_errors_ = false;
+
+       printf("testing process_remaining_frames()... ");
+       if(!decoder->process_remaining_frames())
+               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_whole_stream()... ");
+       if(!decoder->process_whole_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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       ::fclose(decoder->file_);
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+class SeekableStreamDecoder : public FLAC::Decoder::SeekableStream, public DecoderCommon {
+public:
+       SeekableStreamDecoder(): FLAC::Decoder::SeekableStream(), DecoderCommon() { }
+       ~SeekableStreamDecoder() { }
+
+       // from FLAC::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_, 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)flacfilesize_;
+       return ::FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+bool SeekableStreamDecoder::eof_callback()
+{
+       if(error_occurred_)
+               return true;
+
+       return 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, state = %u (%s)\n", msg, (unsigned)((::FLAC__SeekableStreamDecoderState)state), state.as_cstring());
+       else
+               printf("FAILED, state = %u (%s)\n", (unsigned)((::FLAC__SeekableStreamDecoderState)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() != ::FLAC__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_whole_stream()... ");
+       if(!process_whole_stream()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__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+++ unit test: FLAC::Decoder::SeekableStream\n\n");
+
+       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 init()... ");
+       if(decoder->init() != ::FLAC__SEEKABLE_STREAM_DECODER_OK)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       FLAC::Decoder::SeekableStream::State state = decoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__SeekableStreamDecoderState)state), state.as_cstring());
+
+       decoder->current_metadata_number_ = 0;
+       decoder->ignore_errors_ = false;
+       decoder->error_occurred_ = false;
+
+       printf("opening FLAC file... ");
+       decoder->file_ = ::fopen(flacfilename_, "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_metadata()... ");
+       if(!decoder->process_metadata())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_one_frame()... ");
+       if(!decoder->process_one_frame())
+               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_one_frame()... ");
+       if(!decoder->process_one_frame())
+               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_remaining_frames()... ");
+       if(!decoder->process_remaining_frames())
+               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_whole_stream()... ");
+       if(!decoder->process_whole_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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       ::fclose(decoder->file_);
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+class FileDecoder : public FLAC::Decoder::File, public DecoderCommon {
+public:
+       FileDecoder(): FLAC::Decoder::File(), DecoderCommon() { }
+       ~FileDecoder() { }
+
+       // from FLAC::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, state = %u (%s)\n", msg, (unsigned)((::FLAC__FileDecoderState)state), state.as_cstring());
+       else
+               printf("FAILED, state = %u (%s)\n", (unsigned)((::FLAC__FileDecoderState)state), state.as_cstring());
+
+       return false;
+}
+
+bool FileDecoder::test_respond()
+{
+       if(!set_filename(flacfilename_)) {
+               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() != ::FLAC__FILE_DECODER_OK)
+               return die();
+       printf("OK\n");
+
+       current_metadata_number_ = 0;
+
+       printf("testing process_whole_file()... ");
+       if(!process_whole_file()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__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+++ unit test: FLAC::Decoder::File\n\n");
+
+       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(flacfilename_)) {
+               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 init()... ");
+       if(decoder->init() != ::FLAC__FILE_DECODER_OK)
+               return decoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       FLAC::Decoder::File::State state = decoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__FileDecoderState)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_metadata()... ");
+       if(!decoder->process_metadata())
+               return decoder->die("returned false");
+       printf("OK\n");
+
+       printf("testing process_one_frame()... ");
+       if(!decoder->process_one_frame())
+               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_remaining_frames()... ");
+       if(!decoder->process_remaining_frames())
+               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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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_;
+
+       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) file_utils__remove_file(flacfilename_);
+       free_metadata_blocks_();
+
+       return true;
+}
diff --git a/src/test_libFLAC++/decoders.h b/src/test_libFLAC++/decoders.h
new file mode 100644 (file)
index 0000000..a4f7ead
--- /dev/null
@@ -0,0 +1,24 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLACPP_DECODERS_H
+#define FLAC__TEST_LIBFLACPP_DECODERS_H
+
+bool test_decoders();
+
+#endif
diff --git a/src/test_libFLAC++/encoders.cc b/src/test_libFLAC++/encoders.cc
new file mode 100644 (file)
index 0000000..820a5f4
--- /dev/null
@@ -0,0 +1,414 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "encoders.h"
+extern "C" {
+#include "file_utils.h"
+}
+#include "FLAC/assert.h"
+#include "FLAC++/encoder.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static ::FLAC__StreamMetaData streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_;
+static ::FLAC__StreamMetaData *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_ };
+static const unsigned num_metadata_ = 5;
+
+static void *malloc_or_die_(size_t size)
+{
+       void *x = malloc(size);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
+               exit(1);
+       }
+       return x;
+}
+
+static void init_metadata_blocks_()
+{
+       /*
+               most of the actual numbers and data in the blocks don't matter,
+               we just want to make sure the encoder encodes them correctly
+
+               remember, the metadata interface gets tested after the encoders,
+               so we do all the metadata manipulation here without it.
+       */
+
+       /* min/max_framesize and md5sum don't get written at first, so we have to leave them 0 */
+    streaminfo_.is_last = false;
+    streaminfo_.type = ::FLAC__METADATA_TYPE_STREAMINFO;
+    streaminfo_.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+    streaminfo_.data.stream_info.min_blocksize = 576;
+    streaminfo_.data.stream_info.max_blocksize = 576;
+    streaminfo_.data.stream_info.min_framesize = 0;
+    streaminfo_.data.stream_info.max_framesize = 0;
+    streaminfo_.data.stream_info.sample_rate = 44100;
+    streaminfo_.data.stream_info.channels = 1;
+    streaminfo_.data.stream_info.bits_per_sample = 8;
+    streaminfo_.data.stream_info.total_samples = 0;
+       memset(streaminfo_.data.stream_info.md5sum, 0, 16);
+
+    padding_.is_last = false;
+    padding_.type = ::FLAC__METADATA_TYPE_PADDING;
+    padding_.length = 1234;
+
+    seektable_.is_last = false;
+    seektable_.type = ::FLAC__METADATA_TYPE_SEEKTABLE;
+       seektable_.data.seek_table.num_points = 2;
+    seektable_.length = seektable_.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+       seektable_.data.seek_table.points = (::FLAC__StreamMetaData_SeekPoint*)malloc_or_die_(seektable_.data.seek_table.num_points * sizeof(::FLAC__StreamMetaData_SeekPoint));
+       seektable_.data.seek_table.points[0].sample_number = 0;
+       seektable_.data.seek_table.points[0].stream_offset = 0;
+       seektable_.data.seek_table.points[0].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+       seektable_.data.seek_table.points[1].sample_number = ::FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+       seektable_.data.seek_table.points[1].stream_offset = 1000;
+       seektable_.data.seek_table.points[1].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+
+    application1_.is_last = false;
+    application1_.type = ::FLAC__METADATA_TYPE_APPLICATION;
+    application1_.length = 8;
+       memcpy(application1_.data.application.id, "\xfe\xdc\xba\x98", 4);
+       application1_.data.application.data = (FLAC__byte*)malloc_or_die_(4);
+       memcpy(application1_.data.application.data, "\xf0\xe1\xd2\xc3", 4);
+
+    application2_.is_last = false;
+    application2_.type = ::FLAC__METADATA_TYPE_APPLICATION;
+    application2_.length = 4;
+       memcpy(application2_.data.application.id, "\x76\x54\x32\x10", 4);
+       application2_.data.application.data = 0;
+
+    vorbiscomment_.is_last = true;
+    vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+    vorbiscomment_.length = (4 + 8) + 4 + (4 + 5) + (4 + 0);
+       vorbiscomment_.data.vorbis_comment.vendor_string.length = 8;
+       vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(8);
+       memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "flac 1.x", 8);
+       vorbiscomment_.data.vorbis_comment.num_comments = 2;
+       vorbiscomment_.data.vorbis_comment.comments = (::FLAC__StreamMetaData_VorbisComment_Entry*)malloc_or_die_(vorbiscomment_.data.vorbis_comment.num_comments * sizeof(::FLAC__StreamMetaData_VorbisComment_Entry));
+       vorbiscomment_.data.vorbis_comment.comments[0].length = 5;
+       vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
+       memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+       vorbiscomment_.data.vorbis_comment.comments[1].length = 0;
+       vorbiscomment_.data.vorbis_comment.comments[1].entry = 0;
+}
+
+static void free_metadata_blocks_()
+{
+       free(seektable_.data.seek_table.points);
+       free(application1_.data.application.data);
+       free(vorbiscomment_.data.vorbis_comment.vendor_string.entry);
+       free(vorbiscomment_.data.vorbis_comment.comments[0].entry);
+       free(vorbiscomment_.data.vorbis_comment.comments);
+}
+
+class StreamEncoder : public FLAC::Encoder::Stream {
+public:
+       StreamEncoder(): FLAC::Encoder::Stream() { }
+       ~StreamEncoder() { }
+
+       // from FLAC::Encoder::Stream
+       ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame);
+       void metadata_callback(const ::FLAC__StreamMetaData *metadata);
+
+       bool die(const char *msg = 0) const;
+};
+
+::FLAC__StreamEncoderWriteStatus StreamEncoder::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_OK;
+}
+
+void StreamEncoder::metadata_callback(const ::FLAC__StreamMetaData *metadata)
+{
+       (void)metadata;
+}
+
+bool StreamEncoder::die(const char *msg) const
+{
+       State state = get_state();
+
+       if(msg)
+               printf("FAILED, %s, state = %u (%s)\n", msg, (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
+       else
+               printf("FAILED, state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
+
+       return false;
+}
+
+static bool test_stream_encoder()
+{
+       StreamEncoder *encoder;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1] = { samples };
+       unsigned i;
+
+       printf("\n+++ unit test: FLAC::Encoder::Stream\n\n");
+
+       printf("allocating encoder instance... ");
+       encoder = new StreamEncoder();
+       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_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() != ::FLAC__STREAM_ENCODER_OK)
+               return encoder->die();
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       FLAC::Encoder::Stream::State state = encoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
+
+       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");
+
+       /* 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_();
+
+       if(!test_stream_encoder())
+               return false;
+
+       free_metadata_blocks_();
+
+       return true;
+}
diff --git a/src/test_libFLAC++/encoders.h b/src/test_libFLAC++/encoders.h
new file mode 100644 (file)
index 0000000..b418bd3
--- /dev/null
@@ -0,0 +1,24 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLACPP_ENCODERS_H
+#define FLAC__TEST_LIBFLACPP_ENCODERS_H
+
+bool test_encoders();
+
+#endif
diff --git a/src/test_libFLAC++/file_utils.c b/src/test_libFLAC++/file_utils.c
new file mode 100644 (file)
index 0000000..31f8063
--- /dev/null
@@ -0,0 +1,173 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "file_utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include <stdio.h>
+#include <stdlib.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for chmod(), unlink */
+#endif
+#include <sys/stat.h> /* for stat(), chmod() */
+#if defined _WIN32 && !defined __CYGWIN__
+#else
+#include <unistd.h> /* for unlink() */
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+typedef struct {
+       FILE *file;
+} encoder_client_struct;
+
+static FLAC__StreamEncoderWriteStatus encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+       encoder_client_struct *ecd = (encoder_client_struct*)client_data;
+
+       (void)encoder, (void)samples, (void)current_frame;
+
+       if(fwrite(buffer, 1, bytes, ecd->file) != bytes)
+               return FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR;
+       else
+               return FLAC__STREAM_ENCODER_WRITE_OK;
+}
+
+static void encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+       (void)encoder, (void)metadata, (void)client_data;
+}
+
+FLAC__bool file_utils__change_stats(const char *filename, FLAC__bool read_only)
+{
+       struct stat stats;
+
+       if(0 == stat(filename, &stats)) {
+#if !defined _MSC_VER && !defined __MINGW32__
+               if(read_only) {
+                       stats.st_mode &= ~S_IWUSR;
+                       stats.st_mode &= ~S_IWGRP;
+                       stats.st_mode &= ~S_IWOTH;
+               }
+               else {
+                       stats.st_mode |= S_IWUSR;
+                       stats.st_mode |= S_IWGRP;
+                       stats.st_mode |= S_IWOTH;
+               }
+#else
+               if(read_only)
+                       stats.st_mode &= ~S_IWRITE;
+               else
+                       stats.st_mode |= S_IWRITE;
+#endif
+               if(0 != chmod(filename, stats.st_mode))
+                       return false;
+       }
+       else
+               return false;
+
+       return true;
+}
+
+FLAC__bool file_utils__remove_file(const char *filename)
+{
+       return file_utils__change_stats(filename, /*read_only=*/false) && 0 == unlink(filename);
+}
+
+FLAC__bool file_utils__generate_flacfile(const char *output_filename, unsigned *output_filesize, unsigned length, const FLAC__StreamMetaData *streaminfo, FLAC__StreamMetaData **metadata, unsigned num_metadata)
+{
+       FLAC__int32 samples[1024];
+       FLAC__StreamEncoder *encoder;
+       encoder_client_struct encoder_client_data;
+       unsigned i, n;
+
+       FLAC__ASSERT(0 != output_filename);
+       FLAC__ASSERT(0 != streaminfo);
+       FLAC__ASSERT(streaminfo->type == FLAC__METADATA_TYPE_STREAMINFO);
+       FLAC__ASSERT((streaminfo->is_last && num_metadata == 0) || (!streaminfo->is_last && num_metadata > 0));
+
+       if(0 == (encoder_client_data.file = fopen(output_filename, "wb")))
+               return false;
+
+       encoder = FLAC__stream_encoder_new();
+       if(0 == encoder) {
+               fclose(encoder_client_data.file);
+               return false;
+       }
+
+       FLAC__stream_encoder_set_streamable_subset(encoder, true);
+       FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false);
+       FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false);
+       FLAC__stream_encoder_set_channels(encoder, streaminfo->data.stream_info.channels);
+       FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo->data.stream_info.bits_per_sample);
+       FLAC__stream_encoder_set_sample_rate(encoder, streaminfo->data.stream_info.sample_rate);
+       FLAC__stream_encoder_set_blocksize(encoder, streaminfo->data.stream_info.min_blocksize);
+       FLAC__stream_encoder_set_max_lpc_order(encoder, 0);
+       FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0);
+       FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false);
+       FLAC__stream_encoder_set_do_escape_coding(encoder, false);
+       FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false);
+       FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0);
+       FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0);
+       FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0);
+       FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo->data.stream_info.total_samples);
+       FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata);
+       FLAC__stream_encoder_set_write_callback(encoder, encoder_write_callback_);
+       FLAC__stream_encoder_set_metadata_callback(encoder, encoder_metadata_callback_);
+       FLAC__stream_encoder_set_client_data(encoder, &encoder_client_data);
+
+       if(FLAC__stream_encoder_init(encoder) != FLAC__STREAM_ENCODER_OK) {
+               fclose(encoder_client_data.file);
+               return false;
+       }
+
+       /* init the dummy sample buffer */
+       for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+               samples[i] = i & 7;
+
+       while(length > 0) {
+               n = min(length, sizeof(samples) / sizeof(FLAC__int32));
+
+               if(!FLAC__stream_encoder_process_interleaved(encoder, samples, n)) {
+                       fclose(encoder_client_data.file);
+                       return false;
+               }
+
+               length -= n;
+       }
+
+       FLAC__stream_encoder_finish(encoder);
+
+       fclose(encoder_client_data.file);
+
+       FLAC__stream_encoder_delete(encoder);
+
+       if(0 != output_filesize) {
+               struct stat filestats;
+
+               if(stat(output_filename, &filestats) != 0)
+                       return false;
+               else
+                       *output_filesize = (unsigned)filestats.st_size;
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC++/file_utils.h b/src/test_libFLAC++/file_utils.h
new file mode 100644 (file)
index 0000000..5944187
--- /dev/null
@@ -0,0 +1,30 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_FILE_UTILS_H
+#define FLAC__TEST_LIBFLAC_FILE_UTILS_H
+
+#include "FLAC/format.h"
+
+FLAC__bool file_utils__change_stats(const char *filename, FLAC__bool read_only);
+
+FLAC__bool file_utils__remove_file(const char *filename);
+
+FLAC__bool file_utils__generate_flacfile(const char *output_filename, unsigned *output_filesize, unsigned length, const FLAC__StreamMetaData *streaminfo, FLAC__StreamMetaData **metadata, unsigned num_metadata);
+
+#endif
diff --git a/src/test_libFLAC++/main.cc b/src/test_libFLAC++/main.cc
new file mode 100644 (file)
index 0000000..a4db680
--- /dev/null
@@ -0,0 +1,37 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "decoders.h"
+#include "encoders.h"
+#include "metadata.h"
+
+int main(int argc, char *argv[])
+{
+       (void)argc, (void)argv;
+
+       if(!test_encoders())
+               return 1;
+
+       if(!test_decoders())
+               return 1;
+
+       if(!test_metadata())
+               return 1;
+
+       return 0;
+}
diff --git a/src/test_libFLAC++/metadata.cc b/src/test_libFLAC++/metadata.cc
new file mode 100644 (file)
index 0000000..bf1af0e
--- /dev/null
@@ -0,0 +1,36 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "metadata.h"
+#include <stdio.h>
+
+extern int test_metadata_object();
+extern int test_metadata_file_manipulation();
+
+bool test_metadata()
+{
+       if(!test_metadata_object())
+               return false;
+
+       if(!test_metadata_file_manipulation())
+               return false;
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
diff --git a/src/test_libFLAC++/metadata.h b/src/test_libFLAC++/metadata.h
new file mode 100644 (file)
index 0000000..7bb7154
--- /dev/null
@@ -0,0 +1,24 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLACPP_METADATA_H
+#define FLAC__TEST_LIBFLACPP_METADATA_H
+
+bool test_metadata();
+
+#endif
diff --git a/src/test_libFLAC++/metadata_manip.cc b/src/test_libFLAC++/metadata_manip.cc
new file mode 100644 (file)
index 0000000..bf30290
--- /dev/null
@@ -0,0 +1,1528 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+extern "C" {
+#include "file_utils.h"
+}
+#include "FLAC/assert.h"
+#include "FLAC/file_decoder.h"
+#include "FLAC/metadata.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+
+/******************************************************************************
+       The general strategy of these tests (for interface levels 1 and 2) is
+       to create a dummy FLAC file with a known set of initial metadata
+       blocks, then keep a mirror locally of what we expect the metadata to be
+       after each operation.  Then testing becomes a simple matter of running
+       a FLAC__FileDecoder over the dummy file after each operation, comparing
+       the decoded metadata to what's in our local copy.  If there are any
+       differences in the metadata,  or the actual audio data is corrupted, we
+       will catch it while decoding.
+******************************************************************************/
+
+typedef struct {
+       FLAC__bool error_occurred;
+} decoder_client_struct;
+
+typedef struct {
+       FLAC__StreamMetaData *blocks[64];
+       unsigned num_blocks;
+} our_metadata_struct;
+
+static const char *flacfile_ = "metadata.flac";
+
+/* our copy of the metadata in flacfile_ */
+static our_metadata_struct our_metadata_;
+
+/* the current block number that corresponds to the position of the iterator we are testing */
+static unsigned mc_our_block_number_ = 0;
+
+static FLAC__bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static FLAC__bool die_c_(const char *msg, FLAC__MetaData_ChainStatus status)
+{
+       printf("ERROR: %s\n", msg);
+       printf("       status=%s\n", FLAC__MetaData_ChainStatusString[status]);
+       return false;
+}
+
+static FLAC__bool die_ss_(const char *msg, FLAC__MetaData_SimpleIterator *siterator)
+{
+       printf("ERROR: %s\n", msg);
+       printf("       status=%s\n", FLAC__MetaData_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(siterator)]);
+       return false;
+}
+
+/* functions for working with our metadata copy */
+
+static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetaData *block, unsigned position, FLAC__bool copy)
+{
+       unsigned i;
+       FLAC__StreamMetaData *obj = block;
+       FLAC__ASSERT(position < our_metadata_.num_blocks);
+       if(copy) {
+               if(0 == (obj = FLAC__metadata_object_copy(block)))
+                       return die_("during FLAC__metadata_object_copy()");
+       }
+       FLAC__metadata_object_delete(our_metadata_.blocks[position]);
+       our_metadata_.blocks[position] = obj;
+
+       /* set the is_last flags */
+       for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+               our_metadata_.blocks[i]->is_last = false;
+       our_metadata_.blocks[i]->is_last = true;
+
+       return true;
+}
+
+static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetaData *block, unsigned position, FLAC__bool copy)
+{
+       unsigned i;
+       FLAC__StreamMetaData *obj = block;
+       if(copy) {
+               if(0 == (obj = FLAC__metadata_object_copy(block)))
+                       return die_("during FLAC__metadata_object_copy()");
+       }
+       if(position > our_metadata_.num_blocks) {
+               position = our_metadata_.num_blocks;
+       }
+       else {
+               for(i = our_metadata_.num_blocks; i > position; i--)
+                       our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
+       }
+       our_metadata_.blocks[position] = obj;
+       our_metadata_.num_blocks++;
+
+       /* set the is_last flags */
+       for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+               our_metadata_.blocks[i]->is_last = false;
+       our_metadata_.blocks[i]->is_last = true;
+
+       return true;
+}
+
+static void delete_from_our_metadata_(unsigned position)
+{
+       unsigned i;
+       FLAC__ASSERT(position < our_metadata_.num_blocks);
+       FLAC__metadata_object_delete(our_metadata_.blocks[position]);
+       for(i = position; i < our_metadata_.num_blocks - 1; i++)
+               our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
+       our_metadata_.num_blocks--;
+
+       /* set the is_last flags */
+       if(our_metadata_.num_blocks > 0) {
+               for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+                       our_metadata_.blocks[i]->is_last = false;
+               our_metadata_.blocks[i]->is_last = true;
+       }
+}
+
+/* function for comparing our metadata to a FLAC__MetaData_Chain */
+
+static FLAC__bool compare_chain_(FLAC__MetaData_Chain *chain, unsigned current_position, FLAC__StreamMetaData *current_block)
+{
+       unsigned i;
+       FLAC__MetaData_Iterator *iterator;
+       FLAC__StreamMetaData *block;
+       FLAC__bool next_ok = true;
+
+       FLAC__ASSERT(0 != chain);
+
+       printf("\tcomparing chain... ");
+       fflush(stdout);
+
+       if(0 == (iterator = FLAC__metadata_iterator_new()))
+               return die_("allocating memory for iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       i = 0;
+       do {
+               printf("%u... ", i);
+               fflush(stdout);
+
+               if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
+                       FLAC__metadata_iterator_delete(iterator);
+                       return die_("getting block from iterator");
+               }
+
+#if 0
+               if(!compare_block_(our_metadata_.blocks[i], block)) {
+                       FLAC__metadata_iterator_delete(iterator);
+                       return die_("metadata block mismatch");
+               }
+#endif
+
+               i++;
+               next_ok = FLAC__metadata_iterator_next(iterator);
+       } while(i < our_metadata_.num_blocks && next_ok);
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       if(next_ok)
+               return die_("chain has more blocks than expected");
+
+       if(i < our_metadata_.num_blocks)
+               return die_("short block count in chain");
+
+       if(0 != current_block) {
+               printf("CURRENT_POSITION... ");
+               fflush(stdout);
+
+#if 0
+               if(!compare_block_(our_metadata_.blocks[current_position], current_block))
+                       return die_("metadata block mismatch");
+#endif
+       }
+
+       printf("PASSED\n");
+
+       return true;
+}
+
+/* decoder callbacks for checking the file */
+
+static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       (void)decoder, (void)buffer, (void)client_data;
+
+       if(
+               (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+               (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+       ) {
+               printf("content... ");
+               fflush(stdout);
+       }
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void decoder_error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       decoder_client_struct *dcd = (decoder_client_struct*)client_data;
+       (void)decoder;
+
+       dcd->error_occurred = true;
+       printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
+}
+
+/* this version pays no attention to the metadata */
+static void decoder_metadata_callback_null_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+       (void)decoder, (void)metadata, (void)client_data;
+
+       printf("%d... ", mc_our_block_number_);
+       fflush(stdout);
+
+       mc_our_block_number_++;
+}
+
+/* this version is used when we want to compare to our metadata copy */
+static void decoder_metadata_callback_compare_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+       decoder_client_struct *dcd = (decoder_client_struct*)client_data;
+
+       (void)decoder;
+
+       /* don't bother checking if we've already hit an error */
+       if(dcd->error_occurred)
+               return;
+
+       printf("%d... ", mc_our_block_number_);
+       fflush(stdout);
+
+       if(mc_our_block_number_ >= our_metadata_.num_blocks) {
+               (void)die_("got more metadata blocks than expected");
+               dcd->error_occurred = true;
+       }
+       else {
+#if 0
+               if(!compare_block_(our_metadata_.blocks[mc_our_block_number_], metadata)) {
+                       (void)die_("metadata block mismatch");
+                       dcd->error_occurred = true;
+               }
+#endif
+       }
+       mc_our_block_number_++;
+}
+
+static FLAC__bool generate_file_()
+{
+       FLAC__StreamMetaData streaminfo, padding;
+       FLAC__StreamMetaData *metadata[1];
+
+       printf("generating FLAC file for test\n");
+
+       while(our_metadata_.num_blocks > 0)
+               delete_from_our_metadata_(0);
+
+       streaminfo.is_last = false;
+       streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
+       streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+       streaminfo.data.stream_info.min_blocksize = 576;
+       streaminfo.data.stream_info.max_blocksize = 576;
+       streaminfo.data.stream_info.min_framesize = 0;
+       streaminfo.data.stream_info.max_framesize = 0;
+       streaminfo.data.stream_info.sample_rate = 44100;
+       streaminfo.data.stream_info.channels = 1;
+       streaminfo.data.stream_info.bits_per_sample = 8;
+       streaminfo.data.stream_info.total_samples = 0;
+       memset(streaminfo.data.stream_info.md5sum, 0, 16);
+
+       padding.is_last = true;
+       padding.type = FLAC__METADATA_TYPE_PADDING;
+       padding.length = 1234;
+
+       metadata[0] = &padding;
+
+       if(!insert_to_our_metadata_(&streaminfo, 0, /*copy=*/true) || !insert_to_our_metadata_(&padding, 1, /*copy=*/true))
+               return die_("priming our metadata");
+
+       if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
+               return die_("creating the encoded file"); 
+
+       return true;
+}
+
+static FLAC__bool test_file_(const char *filename, void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data))
+{
+       FLAC__FileDecoder *decoder;
+       decoder_client_struct decoder_client_data;
+
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != metadata_callback);
+
+       mc_our_block_number_ = 0;
+       decoder_client_data.error_occurred = false;
+
+       printf("\ttesting '%s'... ", filename);
+       fflush(stdout);
+
+       if(0 == (decoder = FLAC__file_decoder_new()))
+               return die_("couldn't allocate memory");
+
+       FLAC__file_decoder_set_md5_checking(decoder, true);
+       FLAC__file_decoder_set_filename(decoder, filename);
+       FLAC__file_decoder_set_write_callback(decoder, decoder_write_callback_);
+       FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
+       FLAC__file_decoder_set_error_callback(decoder, decoder_error_callback_);
+       FLAC__file_decoder_set_client_data(decoder, &decoder_client_data);
+       FLAC__file_decoder_set_metadata_respond_all(decoder);
+       if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
+               FLAC__file_decoder_finish(decoder);
+               FLAC__file_decoder_delete(decoder);
+               return die_("initializing decoder\n");
+       }
+       if(!FLAC__file_decoder_process_whole_file(decoder)) {
+               FLAC__file_decoder_finish(decoder);
+               FLAC__file_decoder_delete(decoder);
+               return die_("decoding file\n");
+       }
+
+       FLAC__file_decoder_finish(decoder);
+       FLAC__file_decoder_delete(decoder);
+
+       if(decoder_client_data.error_occurred)
+               return false;
+
+       if(mc_our_block_number_ != our_metadata_.num_blocks)
+               return die_("short metadata block count");
+
+       printf("PASSED\n");
+       return true;
+}
+
+static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
+{
+       if(!file_utils__change_stats(filename, read_only))
+        return die_("during file_utils__change_stats()");
+
+       return true;
+}
+
+static FLAC__bool remove_file_(const char *filename)
+{
+       while(our_metadata_.num_blocks > 0)
+               delete_from_our_metadata_(0);
+
+       if(!file_utils__remove_file(filename))
+               return die_("removing file");
+
+       return true;
+}
+
+static FLAC__bool test_level_0_()
+{
+       FLAC__StreamMetaData_StreamInfo streaminfo;
+
+       printf("\n\n++++++ testing level 0 interface\n");
+
+       if(!generate_file_())
+               return false;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_null_))
+               return false;
+
+       if(!FLAC__metadata_get_streaminfo(flacfile_, &streaminfo))
+               return die_("during FLAC__metadata_get_streaminfo()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(streaminfo.channels != 1)
+               return die_("mismatch in streaminfo.channels");
+       if(streaminfo.bits_per_sample != 8)
+               return die_("mismatch in streaminfo.bits_per_sample");
+       if(streaminfo.sample_rate != 44100)
+               return die_("mismatch in streaminfo.sample_rate");
+       if(streaminfo.min_blocksize != 576)
+               return die_("mismatch in streaminfo.min_blocksize");
+       if(streaminfo.max_blocksize != 576)
+               return die_("mismatch in streaminfo.max_blocksize");
+
+       if(!remove_file_(flacfile_))
+               return false;
+
+       return true;
+}
+
+static FLAC__bool test_level_1_()
+{
+       FLAC__MetaData_SimpleIterator *siterator;
+       FLAC__StreamMetaData *block, *app, *padding;
+       FLAC__byte data[1000];
+       unsigned our_current_position = 0;
+
+       printf("\n\n++++++ testing level 1 interface\n");
+
+       /************************************************************/
+
+       printf("simple iterator on read-only file\n");
+
+       if(!generate_file_())
+               return false;
+
+       if(!change_stats_(flacfile_, /*read_only=*/true))
+               return false;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_null_))
+               return false;
+
+       if(0 == (siterator = FLAC__metadata_simple_iterator_new()))
+               return die_("FLAC__metadata_simple_iterator_new()");
+
+       if(!FLAC__metadata_simple_iterator_init(siterator, flacfile_, false))
+               return die_("ERROR: FLAC__metadata_simple_iterator_init()\n");
+
+       printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(siterator));
+       if(FLAC__metadata_simple_iterator_is_writable(siterator))
+               return die_("iterator claims file is writable when it should not be\n");
+
+       printf("iterate forwards\n");
+
+       if(FLAC__metadata_simple_iterator_get_block_type(siterator) != FLAC__METADATA_TYPE_STREAMINFO)
+               return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
+       if(0 == (block = FLAC__metadata_simple_iterator_get_block(siterator)))
+               return die_("getting block 0");
+       if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
+               return die_("expected STREAMINFO type");
+       if(block->is_last)
+               return die_("expected is_last to be false");
+       if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+               return die_("bad STREAMINFO length");
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(block->data.stream_info.channels != 1)
+               return die_("mismatch in channels");
+       if(block->data.stream_info.bits_per_sample != 8)
+               return die_("mismatch in bits_per_sample");
+       if(block->data.stream_info.sample_rate != 44100)
+               return die_("mismatch in sample_rate");
+       if(block->data.stream_info.min_blocksize != 576)
+               return die_("mismatch in min_blocksize");
+       if(block->data.stream_info.max_blocksize != 576)
+               return die_("mismatch in max_blocksize");
+
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("forward iterator ended early");
+       our_current_position++;
+
+       if(FLAC__metadata_simple_iterator_get_block_type(siterator) != FLAC__METADATA_TYPE_PADDING)
+               return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
+       if(0 == (block = FLAC__metadata_simple_iterator_get_block(siterator)))
+               return die_("getting block 1");
+       if(block->type != FLAC__METADATA_TYPE_PADDING)
+               return die_("expected PADDING type");
+       if(!block->is_last)
+               return die_("expected is_last to be true");
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(block->length != 1234)
+               return die_("bad STREAMINFO length");
+
+       if(FLAC__metadata_simple_iterator_next(siterator))
+               return die_("forward iterator returned true but should have returned false");
+
+       printf("iterate backwards\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("reverse iterator ended early");
+       if(FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("reverse iterator returned true but should have returned false");
+
+       printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
+
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, (::FLAC__StreamMetaData*)99, false))
+               printf("PASSED.  FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
+       else
+               return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
+
+       FLAC__metadata_simple_iterator_delete(siterator);
+
+       /************************************************************/
+
+       printf("simple iterator on writable file\n");
+
+       if(!change_stats_(flacfile_, /*read-only=*/false))
+               return false;
+
+       printf("creating APPLICATION block\n");
+
+       if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
+               return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
+       memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+
+       printf("creating PADDING block\n");
+
+       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+               return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
+       padding->length = 20;
+
+       if(0 == (siterator = FLAC__metadata_simple_iterator_new()))
+               return die_("FLAC__metadata_simple_iterator_new()");
+
+       if(!FLAC__metadata_simple_iterator_init(siterator, flacfile_, /*preserve_file_stats=*/false))
+               return die_("ERROR: FLAC__metadata_simple_iterator_init()\n");
+       our_current_position = 0;
+
+       printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(siterator));
+
+       printf("[S]P\ttry to write over STREAMINFO block...\n");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
+               printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
+       else
+               return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
+
+       printf("[S]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]\tinsert PADDING after, don't expand into padding\n");
+       padding->length = 25;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       printf("SP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[P]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]PP\tinsert PADDING after, don't expand into padding\n");
+       padding->length = 30;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+       
+       printf("S[P]PP\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]PPP\tdelete (STREAMINFO block), must fail\n");
+       if(FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false) should have returned false", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]PPP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]PP\tdelete (middle block), replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, true))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, true)", siterator);
+       our_current_position--;
+
+       printf("[S]PPP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]PP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]PP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SP[P]\tdelete (last block), replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, true))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       our_current_position--;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[P]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SP[P]\tdelete (last block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]P\tset STREAMINFO (change sample rate)\n");
+       FLAC__ASSERT(our_current_position == 0);
+       block = FLAC__metadata_simple_iterator_get_block(siterator);
+       block->data.stream_info.sample_rate = 32000;
+       if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, block, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, block, false)", siterator);
+       FLAC__metadata_object_delete(block);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
+       app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return false;
+       our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SA[P]\tset APPLICATION, expand into padding of exceeding size\n");
+       app->data.application.id[0] = 'f'; /* twiddle the id */
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+       if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
+               return false;
+       our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SA[A]P\tset APPLICATION (grow), don't expand into padding\n");
+       app->data.application.id[0] = 'g'; /* twiddle the id */
+       if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, false)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
+       app->data.application.id[0] = 'h'; /* twiddle the id */
+       if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, false)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
+       app->data.application.id[0] = 'i'; /* twiddle the id */
+       if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SA[A]P\tset APPLICATION (shrink), fill in with padding\n");
+       app->data.application.id[0] = 'j'; /* twiddle the id */
+       if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
+               return die_("copying object");
+       our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SA[A]PP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SAA[P]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
+       padding->length = 5;
+       if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, padding, false)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SAAP[P]\tset APPLICATION (grow)\n");
+       app->data.application.id[0] = 'k'; /* twiddle the id */
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, false)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SAAP[A]\tset PADDING (equal)\n");
+       padding->length = 27;
+       if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, padding, false)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SAAP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SAA[P]P\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SA[A]P\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SA[P]\tinsert PADDING after\n");
+       padding->length = 5;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SAP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SA[P]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       our_metadata_.blocks[our_current_position+1]->length = 0;
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       delete_from_our_metadata_(our_current_position+1);
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       delete_from_our_metadata_(our_current_position+1);
+       our_metadata_.blocks[our_current_position]->is_last = true;
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tset PADDING (equal size)\n");
+       padding->length = app->length;
+       if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_set_block(siterator, padding, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(siterator, padding, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[P]\tinsert PADDING after\n");
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SP[P]\tinsert PADDING after\n");
+       padding->length = 5;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, padding, false)", siterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SPP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SP[P]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[P]PP\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(siterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PPP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PPP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       delete_from_our_metadata_(our_current_position+1);
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       our_metadata_.blocks[our_current_position+1]->length = 0;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]PP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]PP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(siterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]P\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(siterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(siterator, false)", siterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+       if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       delete_from_our_metadata_(our_current_position+1);
+       if(!FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(siterator, app, true)", siterator);
+
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("delete simple iterator\n");
+
+       FLAC__metadata_simple_iterator_delete(siterator);
+
+       FLAC__metadata_object_delete(app);
+       FLAC__metadata_object_delete(padding);
+
+       if(!remove_file_(flacfile_))
+               return false;
+
+       return true;
+}
+
+static FLAC__bool test_level_2_()
+{
+       FLAC__MetaData_Iterator *iterator;
+       FLAC__MetaData_Chain *chain;
+       FLAC__StreamMetaData *block, *app, *padding;
+       FLAC__byte data[2000];
+       unsigned our_current_position;
+
+       printf("\n\n++++++ testing level 2 interface\n");
+
+       printf("generate read-only file\n");
+
+       if(!generate_file_())
+               return false;
+
+       if(!change_stats_(flacfile_, /*read_only=*/true))
+               return false;
+
+       printf("create chain\n");
+
+       if(0 == (chain = FLAC__metadata_chain_new()))
+               return die_("allocating chain");
+
+       printf("read chain\n");
+
+       if(!FLAC__metadata_chain_read(chain, flacfile_))
+               return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+       printf("[S]P\ttest initial metadata\n");
+
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("switch file to read-write\n");
+
+       if(!change_stats_(flacfile_, /*read-only=*/false))
+               return false;
+
+       printf("create iterator\n");
+       if(0 == (iterator = FLAC__metadata_iterator_new()))
+               return die_("allocating memory for iterator");
+
+       our_current_position = 0;
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
+               return die_("getting block from iterator");
+
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+       printf("[S]P\tmodify STREAMINFO, write\n");
+
+       block->data.stream_info.sample_rate = 32000;
+       if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+               return die_("copying object");
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/true))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]P\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]\treplace PADDING with identical-size APPLICATION\n");
+       if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
+               return die_("getting block from iterator");
+       if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
+               return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
+       memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+       if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tshrink APPLICATION, don't use padding\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tgrow APPLICATION, don't use padding\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
+       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+               return die_("creating PADDING block");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       padding->length = 0;
+       if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
+               return die_("internal error");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tshrink APPLICATION, use padding, last block is padding\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       our_metadata_.blocks[our_current_position+1]->length = 13;
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
+       if(0 == (app = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("copying object");
+       if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       delete_from_our_metadata_(our_current_position+1);
+       if(!FLAC__metadata_iterator_set_block(iterator, app))
+               return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[A]\tprev\n");
+       if(!FLAC__metadata_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]A\tinsert PADDING before STREAMINFO (should fail)\n");
+       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+               return die_("creating PADDING block");
+       padding->length = 30;
+       if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+               printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
+       else
+               return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
+
+       printf("[S]A\tinsert PADDING after\n");
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
+               return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("S[P]A\tinsert PADDING before\n");
+       if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("creating PADDING block");
+       padding->length = 17;
+       if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+               return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("S[P]PA\tinsert PADDING before\n");
+       if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[our_current_position])))
+               return die_("creating PADDING block");
+       padding->length = 0;
+       if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+               return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("S[P]PPA\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SP[P]PA\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SPP[P]A\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SPPP[A]\tinsert PADDING after\n");
+       if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[1])))
+               return die_("creating PADDING block");
+       padding->length = 57;
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
+               return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("SPPPA[P]\tinsert PADDING before\n");
+       if(0 == (padding = FLAC__metadata_object_copy(our_metadata_.blocks[1])))
+               return die_("creating PADDING block");
+       padding->length = 99;
+       if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+               return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("delete iterator\n");
+       FLAC__metadata_iterator_delete(iterator);
+       our_current_position = 0;
+
+       printf("SPPPAPP\tmerge padding\n");
+       FLAC__metadata_chain_merge_padding(chain);
+       our_metadata_.blocks[1]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
+       our_metadata_.blocks[1]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
+       our_metadata_.blocks[5]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[6]->length);
+       delete_from_our_metadata_(6);
+       delete_from_our_metadata_(3);
+       delete_from_our_metadata_(2);
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SPAP\tsort padding\n");
+       FLAC__metadata_chain_sort_padding(chain);
+       our_metadata_.blocks[3]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[1]->length);
+       delete_from_our_metadata_(1);
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("create iterator\n");
+       if(0 == (iterator = FLAC__metadata_iterator_new()))
+               return die_("allocating memory for iterator");
+
+       our_current_position = 0;
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       printf("[S]AP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[A]P\tdelete middle block, replace with padding\n");
+       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+               return die_("creating PADDING block");
+       padding->length = 71;
+       if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
+               return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("[S]PP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]P\tdelete middle block, don't replace with padding\n");
+       delete_from_our_metadata_(our_current_position--);
+       if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+               return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("[S]P\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]\tdelete last block, replace with padding\n");
+       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+               return die_("creating PADDING block");
+       padding->length = 219;
+       if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+               return die_("copying object");
+       if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
+               return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("[S]P\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[P]\tdelete last block, don't replace with padding\n");
+       delete_from_our_metadata_(our_current_position--);
+       if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+               return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("[S]\tdelete STREAMINFO block, should fail\n");
+       if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+               return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
+
+       if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+               return false;
+
+       printf("delete iterator\n");
+       FLAC__metadata_iterator_delete(iterator);
+       our_current_position = 0;
+
+       printf("S\tmerge padding\n");
+       FLAC__metadata_chain_merge_padding(chain);
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S\tsort padding\n");
+       FLAC__metadata_chain_sort_padding(chain);
+
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+               return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(flacfile_, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("delete chain\n");
+
+       FLAC__metadata_chain_delete(chain);
+
+       if(!remove_file_(flacfile_))
+               return false;
+
+       return true;
+}
+
+bool test_metadata_file_manipulation()
+{
+       printf("\n+++ unit test: metadata manipulation\n\n");
+
+       our_metadata_.num_blocks = 0;
+
+       if(!test_level_0_())
+               return false;
+
+       if(!test_level_1_())
+               return false;
+
+       if(!test_level_2_())
+               return false;
+
+       return true;
+}
diff --git a/src/test_libFLAC++/metadata_object.cc b/src/test_libFLAC++/metadata_object.cc
new file mode 100644 (file)
index 0000000..6ce385f
--- /dev/null
@@ -0,0 +1,379 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "FLAC/assert.h"
+#include "FLAC++/metadata.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+static ::FLAC__StreamMetaData streaminfo_, padding_, seektable_, application_, vorbiscomment_;
+
+static void *malloc_or_die_(size_t size)
+{
+       void *x = malloc(size);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
+               exit(1);
+       }
+       return x;
+}
+
+static void init_metadata_blocks_()
+{
+    streaminfo_.is_last = false;
+    streaminfo_.type = ::FLAC__METADATA_TYPE_STREAMINFO;
+    streaminfo_.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+    streaminfo_.data.stream_info.min_blocksize = 576;
+    streaminfo_.data.stream_info.max_blocksize = 576;
+    streaminfo_.data.stream_info.min_framesize = 0;
+    streaminfo_.data.stream_info.max_framesize = 0;
+    streaminfo_.data.stream_info.sample_rate = 44100;
+    streaminfo_.data.stream_info.channels = 1;
+    streaminfo_.data.stream_info.bits_per_sample = 8;
+    streaminfo_.data.stream_info.total_samples = 0;
+       memset(streaminfo_.data.stream_info.md5sum, 0, 16);
+
+    padding_.is_last = false;
+    padding_.type = ::FLAC__METADATA_TYPE_PADDING;
+    padding_.length = 1234;
+
+    seektable_.is_last = false;
+    seektable_.type = ::FLAC__METADATA_TYPE_SEEKTABLE;
+       seektable_.data.seek_table.num_points = 2;
+    seektable_.length = seektable_.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+       seektable_.data.seek_table.points = (::FLAC__StreamMetaData_SeekPoint*)malloc_or_die_(seektable_.data.seek_table.num_points * sizeof(::FLAC__StreamMetaData_SeekPoint));
+       seektable_.data.seek_table.points[0].sample_number = 0;
+       seektable_.data.seek_table.points[0].stream_offset = 0;
+       seektable_.data.seek_table.points[0].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+       seektable_.data.seek_table.points[1].sample_number = ::FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+       seektable_.data.seek_table.points[1].stream_offset = 1000;
+       seektable_.data.seek_table.points[1].frame_samples = streaminfo_.data.stream_info.min_blocksize;
+
+    application_.is_last = false;
+    application_.type = ::FLAC__METADATA_TYPE_APPLICATION;
+    application_.length = 8;
+       memcpy(application_.data.application.id, "\xfe\xdc\xba\x98", 4);
+       application_.data.application.data = (FLAC__byte*)malloc_or_die_(4);
+       memcpy(application_.data.application.data, "\xf0\xe1\xd2\xc3", 4);
+
+    vorbiscomment_.is_last = true;
+    vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+    vorbiscomment_.length = (4 + 8) + 4 + (4 + 5) + (4 + 0);
+       vorbiscomment_.data.vorbis_comment.vendor_string.length = 8;
+       vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(8);
+       memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "flac 1.x", 8);
+       vorbiscomment_.data.vorbis_comment.num_comments = 2;
+       vorbiscomment_.data.vorbis_comment.comments = (::FLAC__StreamMetaData_VorbisComment_Entry*)malloc_or_die_(vorbiscomment_.data.vorbis_comment.num_comments * sizeof(::FLAC__StreamMetaData_VorbisComment_Entry));
+       vorbiscomment_.data.vorbis_comment.comments[0].length = 5;
+       vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
+       memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+       vorbiscomment_.data.vorbis_comment.comments[1].length = 0;
+       vorbiscomment_.data.vorbis_comment.comments[1].entry = 0;
+}
+
+static void free_metadata_blocks_()
+{
+       free(seektable_.data.seek_table.points);
+       free(application_.data.application.data);
+       free(vorbiscomment_.data.vorbis_comment.vendor_string.entry);
+       free(vorbiscomment_.data.vorbis_comment.comments[0].entry);
+       free(vorbiscomment_.data.vorbis_comment.comments);
+}
+
+bool test_metadata_object_streaminfo()
+{
+       FLAC::Metadata::StreamInfo block;
+       unsigned expected_length;
+
+       printf("\n+++ unit test: metadata objects (libFLAC++)\n\n");
+
+
+       printf("testing FLAC::Metadata::StreamInfo\n");
+
+       printf("testing FLAC::Metadata::StreamInfo::StreamInfo()... ");
+       if(!block.is_valid()) {
+               printf("FAILED, !block.is_valid()\n");
+               return false;
+       }
+       expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+       if(block.get_length() != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+               return false;
+    }
+       printf("OK\n");
+
+       printf("testing FLAC::MetaData::StreamInfo::StreamInfo(const StreamInfo &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(block);
+               if(blockcopy != block) {
+                       printf("FAILED, copy is not identical to original\n");
+                       return false;
+               }
+               printf("OK\n");
+
+               printf("testing FLAC::Metadata::StreamInfo::~StreamInfo()... ");
+       }
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::StreamInfo::operator=(const ::FLAC__StreamMetaData &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(streaminfo_, /*copy=*/true);
+               if(!blockcopy.is_valid()) {
+                       printf("FAILED, !block.is_valid()\n");
+                       return false;
+               }
+               if(blockcopy != streaminfo_) {
+                       printf("FAILED, copy is not identical to original\n");
+                       return false;
+               }
+       }
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::StreamInfo::operator=(const ::FLAC__StreamMetaData *)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(&streaminfo_, /*copy=*/true);
+               if(!blockcopy.is_valid()) {
+                       printf("FAILED, !block.is_valid()\n");
+                       return false;
+               }
+               if(blockcopy != streaminfo_) {
+                       printf("FAILED, copy is not identical to original\n");
+                       return false;
+               }
+       }
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::StreamInfo::operator=(const StreamInfo &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy = block;
+               if(!blockcopy.is_valid()) {
+                       printf("FAILED, !block.is_valid()\n");
+                       return false;
+               }
+               if(blockcopy != block) {
+                       printf("FAILED, copy is not identical to original\n");
+                       return false;
+               }
+       }
+       printf("OK\n");
+
+       return true;
+}
+
+bool test_metadata_object()
+{
+       init_metadata_blocks_();
+
+       if(!test_metadata_object_streaminfo())
+               return false;
+
+       free_metadata_blocks_();
+
+       return true;
+}
+
+#if 0
+
+
+               // ============================================================
+               //
+               //  Metadata objects
+               //
+               // ============================================================
+
+               // NOTE: When the get_*() methods return you a const pointer,
+               // DO NOT disobey and write into it.  Always use the set_*()
+               // methods.
+
+               // base class for all metadata blocks
+               class Prototype {
+               protected:
+                       Prototype(::FLAC__StreamMetaData *object, bool copy);
+                       virtual ~Prototype();
+
+                       void operator=(const Prototype &);
+                       void operator=(const ::FLAC__StreamMetaData &);
+                       void operator=(const ::FLAC__StreamMetaData *);
+
+                       inline bool operator==(const FLAC::Metadata::Prototype &block)
+                       { return ::FLAC__metadata_object_is_equal(object_, block.object_); }
+
+                       virtual void clear();
+
+                       ::FLAC__StreamMetaData *object_;
+               public:
+                       friend class SimpleIterator;
+                       friend class Iterator;
+
+                       inline bool is_valid() const { return 0 != object_; }
+                       inline operator bool() const { return is_valid(); }
+
+                       bool get_is_last() const;
+                       FLAC__MetaDataType get_type() const;
+                       unsigned get_length() const; // NOTE: does not include the header, per spec
+               private:
+                       Prototype(); // Private and undefined so you can't use it
+
+                       // These are used only by Iterator
+                       bool is_reference_;
+                       inline void set_reference(bool x) { is_reference_ = x; }
+               };
+
+               class StreamInfo : public Prototype {
+               public:
+                       unsigned get_min_blocksize() const;
+                       unsigned get_max_blocksize() const;
+                       unsigned get_min_framesize() const;
+                       unsigned get_max_framesize() const;
+                       unsigned get_sample_rate() const;
+                       unsigned get_channels() const;
+                       unsigned get_bits_per_sample() const;
+                       FLAC__uint64 get_total_samples() const;
+                       const FLAC__byte *get_md5sum() const;
+
+                       void set_min_blocksize(unsigned value);
+                       void set_max_blocksize(unsigned value);
+                       void set_min_framesize(unsigned value);
+                       void set_max_framesize(unsigned value);
+                       void set_sample_rate(unsigned value);
+                       void set_channels(unsigned value);
+                       void set_bits_per_sample(unsigned value);
+                       void set_total_samples(FLAC__uint64 value);
+                       void set_md5sum(const FLAC__byte value[16]);
+               };
+
+               class Padding : public Prototype {
+               public:
+                       Padding();
+                       Padding(::FLAC__StreamMetaData *object, bool copy = false);
+                       ~Padding();
+
+                       inline void operator=(const Padding &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
+
+                       void set_length(unsigned length);
+               };
+
+               class Application : public Prototype {
+               public:
+                       Application();
+                       Application(::FLAC__StreamMetaData *object, bool copy = false);
+                       ~Application();
+
+                       inline void operator=(const Application &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
+
+                       const FLAC__byte *get_id() const;
+                       const FLAC__byte *get_data() const;
+
+                       void set_id(FLAC__byte value[4]);
+                       bool set_data(FLAC__byte *data, unsigned length, bool copy = false);
+               };
+
+               class SeekTable : public Prototype {
+               public:
+                       SeekTable();
+                       SeekTable(::FLAC__StreamMetaData *object, bool copy = false);
+                       ~SeekTable();
+
+                       inline void operator=(const SeekTable &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
+
+                       unsigned get_num_points() const;
+                       ::FLAC__StreamMetaData_SeekPoint get_point(unsigned index) const;
+
+                       void set_point(unsigned index, const ::FLAC__StreamMetaData_SeekPoint &point);
+                       bool insert_point(unsigned index, const ::FLAC__StreamMetaData_SeekPoint &point);
+                       bool delete_point(unsigned index);
+
+                       bool is_legal() const;
+               };
+
+               class VorbisComment : public Prototype {
+               public:
+                       class Entry {
+                       public:
+                               Entry();
+                               Entry(const char *field, unsigned field_length);
+                               Entry(const char *field_name, const char *field_value, unsigned field_value_length);
+                               Entry(const Entry &entry);
+                               void operator=(const Entry &entry);
+
+                               virtual ~Entry();
+
+                               virtual bool is_valid() const;
+                               inline operator bool() const { return is_valid(); }
+
+                               unsigned get_field_length() const;
+                               unsigned get_field_name_length() const;
+                               unsigned get_field_value_length() const;
+
+                               ::FLAC__StreamMetaData_VorbisComment_Entry get_entry() const;
+                               const char *get_field() const;
+                               const char *get_field_name() const;
+                               const char *get_field_value() const;
+
+                               bool set_field(const char *field, unsigned field_length);
+                               bool set_field_name(const char *field_name);
+                               bool set_field_value(const char *field_value, unsigned field_value_length);
+                       protected:
+                               bool is_valid_;
+                               ::FLAC__StreamMetaData_VorbisComment_Entry entry_;
+                               char *field_name_;
+                               unsigned field_name_length_;
+                               char *field_value_;
+                               unsigned field_value_length_;
+                       private:
+                               void zero();
+                               void clear();
+                               void clear_entry();
+                               void clear_field_name();
+                               void clear_field_value();
+                               void construct(const char *field, unsigned field_length);
+                               void construct(const char *field_name, const char *field_value, unsigned field_value_length);
+                               void compose_field();
+                               void parse_field();
+                       };
+
+                       VorbisComment();
+                       VorbisComment(::FLAC__StreamMetaData *object, bool copy = false);
+                       ~VorbisComment();
+
+                       inline void operator=(const VorbisComment &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData &object) { Prototype::operator=(object); }
+                       inline void operator=(const ::FLAC__StreamMetaData *object) { Prototype::operator=(object); }
+
+                       unsigned get_num_comments() const;
+                       Entry get_vendor_string() const;
+                       Entry get_comment(unsigned index) const;
+
+                       bool set_vendor_string(const Entry &entry);
+                       bool set_comment(unsigned index, const Entry &entry);
+                       bool insert_comment(unsigned index, const Entry &entry);
+                       bool delete_comment(unsigned index);
+               };
+
+
+
+
+
+#endif
index 3a1217f..1243112 100644 (file)
@@ -1,4 +1,4 @@
-#  test_unit - Simple FLAC unit tester
+#  test_libFLAC - Unit tester for libFLAC
 #  Copyright (C) 2000,2001,2002  Josh Coalson
 #
 #  This program is free software; you can redistribute it and/or
 CFLAGS = @CFLAGS@
 INCLUDES = -I$(top_srcdir)/src/libFLAC/include
 
-noinst_PROGRAMS = test_unit
-test_unit_LDADD = $(top_builddir)/src/libFLAC/libFLAC.la -lm
-test_unit_SOURCES = \
+noinst_PROGRAMS = test_libFLAC
+test_libFLAC = $(top_builddir)/src/libFLAC/libFLAC.la -lm
+test_libFLAC_SOURCES = \
        bitbuffer.c \
        decoders.c \
+       encoders.c \
        file_utils.c \
        main.c \
        metadata.c \
@@ -31,6 +32,7 @@ test_unit_SOURCES = \
        metadata_utils.c \
        bitbuffer.h \
        decoders.h \
+       encoders.h \
        file_utils.h \
        metadata.h \
        metadata_utils.h
index d1b4901..f348b15 100644 (file)
@@ -1,4 +1,4 @@
-#  test_unit - Simple FLAC unit tester
+#  test_libFLAC - Unit tester for libFLAC
 #  Copyright (C) 2000,2001,2002  Josh Coalson
 #
 #  This program is free software; you can redistribute it and/or
 # GNU makefile
 #
 
-PROGRAM_NAME = test_unit
+PROGRAM_NAME = test_libFLAC
 INCLUDES     = -I../libFLAC/include -I../../include
 LIBS         = -lFLAC -lm
 OBJS = \
        bitbuffer.o \
        decoders.o \
+       encoders.o \
        file_utils.o \
        main.o \
        metadata.o \
index eb0a168..ab6ef53 100644 (file)
@@ -1,4 +1,4 @@
-#  test_unit - Simple FLAC unit tester\r
+#  test_libFLAC - Unit tester for libFLAC\r
 #  Copyright (C) 2001,2002  Josh Coalson\r
 #\r
 #  This program is free software; you can redistribute it and/or\r
@@ -28,6 +28,7 @@
 C_FILES= \\r
        bitbuffer.c \\r
        decoders.c \\r
+       encoders.c \\r
        file_utils.c \\r
        main.c \\r
        metadata.c \\r
@@ -37,11 +38,11 @@ C_FILES= \
 \r
 OBJS= $(C_FILES:.c=.obj)\r
 \r
-all: test_unit.exe\r
+all: test_libFLAC.exe\r
 \r
-test_unit.exe: $(OBJS)\r
+test_libFLAC.exe: $(OBJS)\r
        link.exe /libpath:"..\..\obj\lib" -out:../../obj/bin/$*.exe $(OBJS) libFLAC.lib\r
 \r
 clean:\r
        -del *.obj *.pch\r
-       -del ..\..\obj\bin\test_unit.exe\r
+       -del ..\..\obj\bin\test_libFLAC.exe\r
index 75f8c51..e50da77 100644 (file)
@@ -1,4 +1,4 @@
-/* test_unit - Simple FLAC unit tester
+/* test_libFLAC - Unit tester for libFLAC
  * Copyright (C) 2000,2001,2002  Josh Coalson
  *
  * This program is free software; you can redistribute it and/or
@@ -47,7 +47,7 @@ static FLAC__bool dummy_read_callback(FLAC__byte buffer[], unsigned *bytes, void
        return true;
 }
 
-int test_bitbuffer()
+FLAC__bool test_bitbuffer()
 {
        FLAC__BitBuffer *bb, *bb_zero, *bb_one, *bbcopy;
        FLAC__bool ok;
@@ -74,13 +74,13 @@ int test_bitbuffer()
        ok = FLAC__bitbuffer_clear(bb) && FLAC__bitbuffer_clear(bb_zero) && FLAC__bitbuffer_clear(bb_one) && FLAC__bitbuffer_clear(bbcopy);
        printf("%s\n", ok?"OK":"FAILED");
        if(!ok)
-               return 1;
+               return false;
 
        printf("setting up bb_one... ");
        ok = FLAC__bitbuffer_write_raw_uint32(bb_one, 1, 7) && FLAC__bitbuffer_read_raw_uint32(bb_one, &i, 6, dummy_read_callback, 0);
        printf("%s\n", ok?"OK":"FAILED");
        if(!ok)
-               return 1;
+               return false;
        FLAC__bitbuffer_dump(bb_one, stdout);
 
        printf("capacity = %u\n", bb->capacity);
@@ -103,27 +103,27 @@ int test_bitbuffer()
        if(!ok) {
                printf("FAILED\n");
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->blurbs != sizeof(test_pattern1)) {
                printf("FAILED byte count %u != %u\n", bb->blurbs, sizeof(test_pattern1));
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->bits != 0) {
                printf("FAILED bit count %u != 0\n", bb->bits);
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->total_bits != 8*bb->blurbs+bb->bits) {
                printf("FAILED total_bits count %u != %u (%u:%u)\n", bb->total_bits, 8*bb->blurbs+bb->bits, bb->blurbs, bb->bits);
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(memcmp(bb->buffer, test_pattern1, sizeof(FLAC__byte)*sizeof(test_pattern1)) != 0) {
                printf("FAILED pattern match\n");
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        printf("OK\n");
        FLAC__bitbuffer_dump(bb, stdout);
@@ -133,27 +133,27 @@ int test_bitbuffer()
        if(!ok) {
                printf("FAILED\n");
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->blurbs != sizeof(test_pattern1)) {
                printf("FAILED byte count %u != %u\n", bb->blurbs, sizeof(test_pattern1));
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->bits != 6) {
                printf("FAILED bit count %u != 6\n", bb->bits);
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->total_bits != 8*bb->blurbs+bb->bits) {
                printf("FAILED total_bits count %u != %u (%u:%u)\n", bb->total_bits, 8*bb->blurbs+bb->bits, bb->blurbs, bb->bits);
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(memcmp(bb->buffer, test_pattern1, sizeof(FLAC__byte)*sizeof(test_pattern1)) != 0 || bb->buffer[bb->blurbs] != 0x3d) {
                printf("FAILED pattern match\n");
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        printf("OK\n");
        FLAC__bitbuffer_dump(bb, stdout);
@@ -163,27 +163,27 @@ int test_bitbuffer()
        if(!ok) {
                printf("FAILED\n");
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->blurbs != sizeof(test_pattern1)) {
                printf("FAILED byte count %u != %u\n", bb->blurbs, sizeof(test_pattern1));
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->bits != 6) {
                printf("FAILED bit count %u != 6\n", bb->bits);
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;
        }
        if(bb->total_bits != 8*bb->blurbs+bb->bits) {
                printf("FAILED total_bits count %u != %u (%u:%u)\n", bb->total_bits, 8*bb->blurbs+bb->bits, bb->blurbs, bb->bits);
                FLAC__bitbuffer_dump(bb, stdout);
-               return 1;
+               return false;